feat: refactor user extension handling and update MPW generation

- Updated README.md to clarify the status of KianV RV32IMA and PicoRV32 in the user-extension map.
- Modified Makefile to include USER_EXTENSIONS_SOURCE in MPW variant stamp dependencies.
- Enhanced integration README.md to better describe the relationship between user_extensions.json and mpw.toml.
- Updated generate_user_extensions.py to include design_id in ExtensionTarget and enforce unique design IDs.
- Changed user_extensions.json schema version to 2 and added design_id fields for core and IP targets.
- Refactored generate_mpw.py to support the new manifest structure and validate design selections.
- Adjusted sysctrl_tb.sv test cases to reflect changes in user core reset states.
- Enhanced test_opipsram.py to utilize ccache for improved compilation performance.
- Updated test_script_tools.py to include new tests for active manifest generation.
- Modified test_user_extensions.py to validate isolated scalar bindings and reject duplicate design selections.
This commit is contained in:
maksyuki committed 2026-08-22 10:53:03 +08:00
1 parent e219973c45
commit 8276903600
23 files changed
+1058 -2979

No files matched your search

+3 -4
View File
@@ -19,8 +19,8 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
## Highlights
- A fixed Hazard3 management core with a permanent JTAG Debug Module, plus
software-selected user-core and user-IP extension slots, including PicoRV32
at user-core slot C5.
software-selected user-core and user-IP extension slots. The active user
cores are KianV RV32I, SERV, FemtoRV32, and DarkRISCV at slots C0-C3.
- A documented [Tiny/Mini/Std/Pro product direction](docs/soc-family-positioning.md)
anchored by Mini and a trusted Hazard3 management model. The higher Linux,
graphics, AI, and RV64 configurations are roadmap targets, not supported
@@ -67,8 +67,7 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
The committed profiles are the supported starting points. They select an ISA,
PDK, application, linker layout, and optional features as one reproducible
configuration. The management core is fixed to Hazard3. The user-extension
fabric exposes stable C0-C5 user-core slots and software selects one active
user core.
fabric exposes C0-C3 user-core slots and software selects one active user core.
| Profile | ISA | Application | Coverage |
| --- | --- | --- | --- |
+2 -2
View File
@@ -3,8 +3,8 @@
This directory contains committed Make configuration profiles. Each profile
selects SoC, PDK, ISA, CSR support, application, linker layout, and the
supported validation tier. The management core is fixed to Hazard3 with its
JTAG Debug Module enabled. The user-extension fabric exposes stable C0-C5
slots, with PicoRV32 at C5.
JTAG Debug Module enabled. The user-extension fabric exposes C0-C3 slots for
KianV RV32I, SERV, FemtoRV32, and DarkRISCV.
`ci/` contains pull-request profiles, `cluster/` contains configurations
requiring site tools or PDKs, and `benchmark/` contains fixed-workload baseline
+2 -2
View File
@@ -13,8 +13,8 @@ a second SoC bus master. Debugger memory operations execute through the halted
hart and remain subject to the AXI4 interconnect access policy. User cores,
peripherals, clocks, and pad control stay outside the debug-reset scope.
PicoRV32 is available as software-selected user core C5 through mini-ver-mpw;
it is not a management-core option and has no management Debug Module.
The C0-C3 user cores are software-selected through mini-ver-mpw. They are not
management-core options and do not have a management Debug Module.
## Reset And Clocking
+1 -1
View File
@@ -119,7 +119,7 @@ digraph mini_soc_block_diagram {
];
user_core [
fillcolor="#DDF2E3",
label="Selected user core\nC0-C5, one active\nPicoRV32 at C5"
label="Selected user core\nC0-C3, one active\nKianV / SERV / FemtoRV32 / DarkRISCV"
];
dma [
fillcolor="#DDF2E3",
+54 -54
View File
@@ -225,9 +225,9 @@
<!-- debug_module&#45;&gt;timers -->
<g id="edge7" class="edge">
<title>debug_module&#45;&gt;timers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M2557.3,-671.05C2509.22,-665.15 2455,-658.48 2455,-658.48 2455,-658.48 1325,-581.98 1325,-581.98 1325,-581.98 1325,-581.98 1325,-356 1325,-356 1320,-289 1320,-289 1320,-289 991,-266 991,-266 991,-266 984.42,-264.48 974.38,-262.17"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M2557.3,-671.05C2509.22,-665.15 2455,-658.48 2455,-658.48 2455,-658.48 1389,-581.98 1389,-581.98 1389,-581.98 1389,-581.98 1389,-356 1389,-356 1384,-289 1384,-289 1384,-289 991,-266 991,-266 991,-266 984.42,-264.48 974.38,-262.17"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="974.69,-259.72 967.32,-260.54 973.59,-264.5 974.69,-259.72"/>
<text text-anchor="middle" x="1336" y="-464.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
<text text-anchor="middle" x="1400" y="-464.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
</g>
<!-- mgmt_adapter&#45;&gt;fabric -->
<g id="edge10" class="edge">
@@ -239,32 +239,32 @@
<!-- user_core -->
<g id="node13" class="node">
<title>user_core</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M2847,-603.48C2847,-603.48 2771,-603.48 2771,-603.48 2765,-603.48 2759,-597.48 2759,-591.48 2759,-591.48 2759,-570.48 2759,-570.48 2759,-564.48 2765,-558.48 2771,-558.48 2771,-558.48 2847,-558.48 2847,-558.48 2853,-558.48 2859,-564.48 2859,-570.48 2859,-570.48 2859,-591.48 2859,-591.48 2859,-597.48 2853,-603.48 2847,-603.48"/>
<text text-anchor="middle" x="2809" y="-589.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="2809" y="-578.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C5, one active</text>
<text text-anchor="middle" x="2809" y="-567.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M2847.5,-603.48C2847.5,-603.48 2668.5,-603.48 2668.5,-603.48 2662.5,-603.48 2656.5,-597.48 2656.5,-591.48 2656.5,-591.48 2656.5,-570.48 2656.5,-570.48 2656.5,-564.48 2662.5,-558.48 2668.5,-558.48 2668.5,-558.48 2847.5,-558.48 2847.5,-558.48 2853.5,-558.48 2859.5,-564.48 2859.5,-570.48 2859.5,-570.48 2859.5,-591.48 2859.5,-591.48 2859.5,-597.48 2853.5,-603.48 2847.5,-603.48"/>
<text text-anchor="middle" x="2758" y="-589.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
<text text-anchor="middle" x="2758" y="-578.48" font-family="Arial" font-size="10.00" fill="#111827">C0&#45;C3, one active</text>
<text text-anchor="middle" x="2758" y="-567.48" font-family="Arial" font-size="10.00" fill="#111827">KianV / SERV / FemtoRV32 / DarkRISCV</text>
</g>
<!-- user_core&#45;&gt;fabric -->
<g id="edge11" class="edge">
<title>user_core&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2801.48,-558.34C2796.79,-544.85 2790.6,-527.03 2784.95,-510.75"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2787.17,-509.7 2782.56,-503.89 2782.54,-511.31 2787.17,-509.7"/>
<text text-anchor="middle" x="2801" y="-529.08" font-family="Arial" font-size="8.00" fill="#374151">AXI4</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2760.31,-558.34C2761.74,-544.97 2763.63,-527.34 2765.35,-511.19"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2767.83,-511.11 2766.14,-503.89 2762.95,-510.59 2767.83,-511.11"/>
<text text-anchor="middle" x="2772" y="-529.08" font-family="Arial" font-size="8.00" fill="#374151">AXI4</text>
</g>
<!-- dma -->
<g id="node14" class="node">
<title>dma</title>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1851,-603.48C1851,-603.48 1703,-603.48 1703,-603.48 1697,-603.48 1691,-597.48 1691,-591.48 1691,-591.48 1691,-570.48 1691,-570.48 1691,-564.48 1697,-558.48 1703,-558.48 1703,-558.48 1851,-558.48 1851,-558.48 1857,-558.48 1863,-564.48 1863,-570.48 1863,-570.48 1863,-591.48 1863,-591.48 1863,-597.48 1857,-603.48 1851,-603.48"/>
<text text-anchor="middle" x="1777" y="-589.48" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
<text text-anchor="middle" x="1777" y="-578.48" font-family="Arial" font-size="10.00" fill="#111827">4&#45;channel native AXI4 burst master</text>
<text text-anchor="middle" x="1777" y="-567.48" font-family="Arial" font-size="10.00" fill="#111827">APB4 target, AXI4&#45;Stream, IRQ20</text>
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1898,-603.48C1898,-603.48 1750,-603.48 1750,-603.48 1744,-603.48 1738,-597.48 1738,-591.48 1738,-591.48 1738,-570.48 1738,-570.48 1738,-564.48 1744,-558.48 1750,-558.48 1750,-558.48 1898,-558.48 1898,-558.48 1904,-558.48 1910,-564.48 1910,-570.48 1910,-570.48 1910,-591.48 1910,-591.48 1910,-597.48 1904,-603.48 1898,-603.48"/>
<text text-anchor="middle" x="1824" y="-589.48" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
<text text-anchor="middle" x="1824" y="-578.48" font-family="Arial" font-size="10.00" fill="#111827">4&#45;channel native AXI4 burst master</text>
<text text-anchor="middle" x="1824" y="-567.48" font-family="Arial" font-size="10.00" fill="#111827">APB4 target, AXI4&#45;Stream, IRQ20</text>
</g>
<!-- dma&#45;&gt;fabric -->
<g id="edge12" class="edge">
<title>dma&#45;&gt;fabric</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1863.39,-570.22C2028.43,-551.56 2391.09,-510.57 2604.34,-486.47"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2604.87,-488.87 2611.55,-485.65 2604.32,-484 2604.87,-488.87"/>
<text text-anchor="middle" x="2252" y="-529.08" font-family="Arial" font-size="8.00" fill="#374151">AXI4</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1910.04,-569.78C2067.47,-551.1 2404.28,-511.14 2606.51,-487.14"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2606.99,-489.55 2613.65,-486.29 2606.41,-484.69 2606.99,-489.55"/>
<text text-anchor="middle" x="2277" y="-529.08" font-family="Arial" font-size="8.00" fill="#374151">AXI4</text>
</g>
<!-- stream_io -->
<g id="node24" class="node">
@@ -278,8 +278,8 @@
<!-- dma&#45;&gt;stream_io -->
<g id="edge13" class="edge">
<title>dma&#45;&gt;stream_io</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1870.52,-575.36C2133.25,-562.37 2859,-526.48 2859,-526.48 2859,-526.48 3376,-503.48 3376,-503.48 3376,-503.48 4267,-266 4267,-266 4267,-266 4269.6,-265.28 4273.96,-264.06"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1870.13,-572.93 1863.26,-575.72 1870.37,-577.82 1870.13,-572.93"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1917.05,-575.17C2171.32,-562.03 2859,-526.48 2859,-526.48 2859,-526.48 3376,-503.48 3376,-503.48 3376,-503.48 4267,-266 4267,-266 4267,-266 4269.6,-265.28 4273.96,-264.06"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1916.88,-572.73 1910.02,-575.54 1917.14,-577.62 1916.88,-572.73"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="4274.81,-266.37 4280.9,-262.13 4273.5,-261.65 4274.81,-266.37"/>
<text text-anchor="middle" x="3793.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">AXI4&#45;Stream</text>
</g>
@@ -294,9 +294,9 @@
<!-- dma&#45;&gt;uart0 -->
<g id="edge43" class="edge">
<title>dma&#45;&gt;uart0</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1770.61,-558.11C1750.84,-490.44 1692,-289 1692,-289 1692,-289 1668.98,-276.49 1645.97,-263.98"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1647.14,-261.83 1639.82,-260.64 1644.8,-266.14 1647.14,-261.83"/>
<text text-anchor="middle" x="1746.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">TX/RX data</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1813.2,-558.38C1781.67,-495.33 1692,-316 1692,-316 1692,-316 1682,-289 1682,-289 1682,-289 1661.97,-276.79 1641.72,-264.44"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1642.98,-262.34 1635.73,-260.79 1640.43,-266.52 1642.98,-262.34"/>
<text text-anchor="middle" x="1758.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">TX/RX data</text>
</g>
<!-- i2c_controllers -->
<g id="node26" class="node">
@@ -309,9 +309,9 @@
<!-- dma&#45;&gt;i2c_controllers -->
<g id="edge47" class="edge">
<title>dma&#45;&gt;i2c_controllers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1757.01,-558.11C1695.15,-490.44 1511,-289 1511,-289 1511,-289 1468.1,-275.68 1426.59,-262.79"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1427.09,-260.38 1419.68,-260.64 1425.64,-265.06 1427.09,-260.38"/>
<text text-anchor="middle" x="1657" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">DATA_CMD / RXDATA</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1801.29,-558.27C1777.64,-535.65 1744,-503.48 1744,-503.48 1744,-503.48 1646,-407 1646,-407 1646,-407 1555,-316 1555,-316 1555,-316 1534,-289 1534,-289 1534,-289 1484.19,-275.46 1436.4,-262.48"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1436.77,-260.04 1429.37,-260.57 1435.48,-264.77 1436.77,-260.04"/>
<text text-anchor="middle" x="1687" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">DATA_CMD / RXDATA</text>
</g>
<!-- ws2812 -->
<g id="node29" class="node">
@@ -324,9 +324,9 @@
<!-- dma&#45;&gt;ws2812 -->
<g id="edge41" class="edge">
<title>dma&#45;&gt;ws2812</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1777.38,-558.11C1778.54,-490.44 1782,-289 1782,-289 1782,-289 1791.31,-277.91 1801.17,-266.18"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1803.07,-267.72 1805.7,-260.79 1799.32,-264.57 1803.07,-267.72"/>
<text text-anchor="middle" x="1807.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1824,-558.4C1824,-499.33 1824,-335.03 1824,-268.02"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1826.45,-267.71 1824,-260.71 1821.55,-267.71 1826.45,-267.71"/>
<text text-anchor="middle" x="1851.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
</g>
<!-- fault -->
<g id="node16" class="node">
@@ -360,16 +360,16 @@
<!-- apb4_periph -->
<g id="node18" class="node">
<title>apb4_periph</title>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1922.5,-375C1922.5,-375 1817.5,-375 1817.5,-375 1811.5,-375 1805.5,-369 1805.5,-363 1805.5,-363 1805.5,-351 1805.5,-351 1805.5,-345 1811.5,-339 1817.5,-339 1817.5,-339 1922.5,-339 1922.5,-339 1928.5,-339 1934.5,-345 1934.5,-351 1934.5,-351 1934.5,-363 1934.5,-363 1934.5,-369 1928.5,-375 1922.5,-375"/>
<text text-anchor="middle" x="1870" y="-360" font-family="Arial" font-size="10.00" fill="#111827">AXI42APB</text>
<text text-anchor="middle" x="1870" y="-349" font-family="Arial" font-size="10.00" fill="#111827">APB4 configuration plane</text>
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1969.5,-375C1969.5,-375 1864.5,-375 1864.5,-375 1858.5,-375 1852.5,-369 1852.5,-363 1852.5,-363 1852.5,-351 1852.5,-351 1852.5,-345 1858.5,-339 1864.5,-339 1864.5,-339 1969.5,-339 1969.5,-339 1975.5,-339 1981.5,-345 1981.5,-351 1981.5,-351 1981.5,-363 1981.5,-363 1981.5,-369 1975.5,-375 1969.5,-375"/>
<text text-anchor="middle" x="1917" y="-360" font-family="Arial" font-size="10.00" fill="#111827">AXI42APB</text>
<text text-anchor="middle" x="1917" y="-349" font-family="Arial" font-size="10.00" fill="#111827">APB4 configuration plane</text>
</g>
<!-- fabric&#45;&gt;apb4_periph -->
<g id="edge17" class="edge">
<title>fabric&#45;&gt;apb4_periph</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2614,-447.07C2417.16,-423.5 2086.85,-383.96 1941.89,-366.61"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1941.95,-364.15 1934.71,-365.75 1941.36,-369.01 1941.95,-364.15"/>
<text text-anchor="middle" x="2286.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">AXI4 config</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2616.02,-446.29C2430.51,-422.86 2126.63,-384.48 1988.89,-367.08"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1988.91,-364.61 1981.66,-366.17 1988.29,-369.47 1988.91,-364.61"/>
<text text-anchor="middle" x="2312.5" y="-400.6" font-family="Arial" font-size="8.00" fill="#374151">AXI4 config</text>
</g>
<!-- apb4_system -->
<g id="node19" class="node">
@@ -411,16 +411,16 @@
<!-- apb4_periph&#45;&gt;sysctrl -->
<g id="edge19" class="edge">
<title>apb4_periph&#45;&gt;sysctrl</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1922.09,-338.92C1955.25,-328.05 1992,-316 1992,-316 1992,-316 2070,-289 2070,-289 2070,-289 2166,-266 2166,-266 2166,-266 2171.79,-264.54 2180.67,-262.3"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1957.99,-338.92C1984.08,-328.05 2013,-316 2013,-316 2013,-316 2070,-289 2070,-289 2070,-289 2166,-266 2166,-266 2166,-266 2171.79,-264.54 2180.67,-262.3"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2181.47,-264.62 2187.65,-260.54 2180.27,-259.87 2181.47,-264.62"/>
<text text-anchor="middle" x="2080.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- apb4_periph&#45;&gt;clint -->
<g id="edge20" class="edge">
<title>apb4_periph&#45;&gt;clint</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1805.28,-339.82C1803.2,-339.3 1802,-339 1802,-339 1802,-339 1430,-316 1430,-316 1430,-316 1329,-289 1329,-289 1329,-289 554,-266 554,-266 554,-266 549.74,-264.68 543.1,-262.62"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1852.28,-339.82C1850.2,-339.3 1849,-339 1849,-339 1849,-339 1453,-316 1453,-316 1453,-316 1392,-289 1392,-289 1392,-289 554,-266 554,-266 554,-266 549.74,-264.68 543.1,-262.62"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="543.81,-260.27 536.39,-260.54 542.35,-264.95 543.81,-260.27"/>
<text text-anchor="middle" x="1440.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<text text-anchor="middle" x="1463.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- apb4_periph_targets -->
<g id="node22" class="node">
@@ -433,23 +433,23 @@
<!-- apb4_periph&#45;&gt;apb4_periph_targets -->
<g id="edge21" class="edge">
<title>apb4_periph&#45;&gt;apb4_periph_targets</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1894.86,-338.99C1923.38,-319.48 1970.43,-287.28 2003.43,-264.71"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2005.02,-266.59 2009.41,-260.61 2002.25,-262.54 2005.02,-266.59"/>
<text text-anchor="middle" x="1975.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1935.03,-338.99C1955.39,-319.78 1988.78,-288.28 2012.64,-265.76"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2014.47,-267.41 2017.88,-260.82 2011.1,-263.84 2014.47,-267.41"/>
<text text-anchor="middle" x="1996.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- apb4_periph&#45;&gt;uart0 -->
<g id="edge22" class="edge">
<title>apb4_periph&#45;&gt;uart0</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1844,-338.92C1813.78,-319.07 1768,-289 1768,-289 1768,-289 1723.05,-275.62 1679.65,-262.71"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1680.12,-260.29 1672.71,-260.64 1678.72,-264.98 1680.12,-260.29"/>
<text text-anchor="middle" x="1816.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1883.35,-338.92C1844.24,-319.07 1785,-289 1785,-289 1785,-289 1734.71,-275.41 1686.57,-262.4"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1687.2,-260.03 1679.8,-260.57 1685.92,-264.76 1687.2,-260.03"/>
<text text-anchor="middle" x="1845.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- apb4_periph&#45;&gt;i2c_controllers -->
<g id="edge23" class="edge">
<title>apb4_periph&#45;&gt;i2c_controllers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1814.92,-338.92C1779.86,-328.05 1741,-316 1741,-316 1741,-316 1692,-289 1692,-289 1692,-289 1469,-266 1469,-266 1469,-266 1462.18,-264.45 1451.81,-262.1"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1852.33,-339.73C1808.31,-328.66 1758,-316 1758,-316 1758,-316 1683,-289 1683,-289 1683,-289 1469,-266 1469,-266 1469,-266 1462.18,-264.45 1451.81,-262.1"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1452.29,-259.7 1444.92,-260.54 1451.2,-264.47 1452.29,-259.7"/>
<text text-anchor="middle" x="1751.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<text text-anchor="middle" x="1768.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- gpio_controller -->
<g id="node27" class="node">
@@ -462,7 +462,7 @@
<!-- apb4_periph&#45;&gt;gpio_controller -->
<g id="edge24" class="edge">
<title>apb4_periph&#45;&gt;gpio_controller</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1934.55,-352.83C2127.08,-343.37 2684,-316 2684,-316 2684,-316 2684,-289 2684,-289 2684,-289 2628.59,-275.35 2575.67,-262.32"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1981.73,-352.62C2166.65,-342.98 2684,-316 2684,-316 2684,-316 2684,-289 2684,-289 2684,-289 2628.59,-275.35 2575.67,-262.32"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2575.95,-259.86 2568.56,-260.57 2574.77,-264.62 2575.95,-259.86"/>
<text text-anchor="middle" x="2704" y="-305.1" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<text text-anchor="middle" x="2704" y="-296.1" font-family="Arial" font-size="8.00" fill="#374151">user/admin</text>
@@ -470,16 +470,16 @@
<!-- apb4_periph&#45;&gt;timers -->
<g id="edge25" class="edge">
<title>apb4_periph&#45;&gt;timers</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1805.23,-346.37C1725.63,-334.53 1601,-316 1601,-316 1601,-316 1511,-289 1511,-289 1511,-289 991,-266 991,-266 991,-266 984.42,-264.48 974.38,-262.17"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1852.4,-348.05C1757.62,-336.38 1592,-316 1592,-316 1592,-316 1534,-289 1534,-289 1534,-289 991,-266 991,-266 991,-266 984.42,-264.48 974.38,-262.17"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="974.69,-259.72 967.32,-260.54 973.59,-264.5 974.69,-259.72"/>
<text text-anchor="middle" x="1611.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<text text-anchor="middle" x="1602.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- apb4_periph&#45;&gt;ws2812 -->
<g id="edge26" class="edge">
<title>apb4_periph&#45;&gt;ws2812</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1863.31,-338.99C1855.95,-320.26 1843.99,-289.86 1835.2,-267.48"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1837.42,-266.44 1832.58,-260.82 1832.86,-268.23 1837.42,-266.44"/>
<text text-anchor="middle" x="1863.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1908.5,-338.75C1898.72,-318.89 1884,-289 1884,-289 1884,-289 1870.21,-277.51 1855.86,-265.55"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1857.09,-263.38 1850.14,-260.79 1853.95,-267.15 1857.09,-263.38"/>
<text text-anchor="middle" x="1906.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- apb4_system_targets -->
<g id="node30" class="node">
@@ -513,9 +513,9 @@
<!-- apb4_system&#45;&gt;wdg -->
<g id="edge31" class="edge">
<title>apb4_system&#45;&gt;wdg</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M3040.86,-354.82C2775.92,-348.22 1484,-316 1484,-316 1484,-316 1453,-289 1453,-289 1453,-289 758,-266 758,-266 758,-266 752.59,-264.57 744.26,-262.36"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M3040.68,-354.8C2777.62,-348.15 1507,-316 1507,-316 1507,-316 1476,-289 1476,-289 1476,-289 758,-266 758,-266 758,-266 752.59,-264.57 744.26,-262.36"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="744.75,-259.96 737.36,-260.54 743.5,-264.7 744.75,-259.96"/>
<text text-anchor="middle" x="1494.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
<text text-anchor="middle" x="1517.5" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">APB4</text>
</g>
<!-- crc -->
<g id="node33" class="node">
@@ -757,9 +757,9 @@
<!-- rtc&#45;&gt;sysctrl -->
<g id="edge56" class="edge">
<title>rtc&#45;&gt;sysctrl</title>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1208.38,-260.53C1222.3,-263.75 1232,-266 1232,-266 1232,-266 1628,-297 1628,-297 1628,-297 1686,-297 1686,-297 1686,-297 2166,-266 2166,-266 2166,-266 2171.45,-264.57 2179.89,-262.37"/>
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1208.38,-260.53C1222.3,-263.75 1232,-266 1232,-266 1232,-266 1619,-297 1619,-297 1619,-297 1677,-297 1677,-297 1677,-297 2166,-266 2166,-266 2166,-266 2171.45,-264.57 2179.89,-262.37"/>
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2180.73,-264.68 2186.88,-260.53 2179.49,-259.94 2180.73,-264.68"/>
<text text-anchor="middle" x="1657" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">wake live / sticky</text>
<text text-anchor="middle" x="1648" y="-300.6" font-family="Arial" font-size="8.00" fill="#374151">wake live / sticky</text>
</g>
<!-- rtc&#45;&gt;irq -->
<g id="edge55" class="edge">

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

+1 -1
View File
@@ -133,7 +133,7 @@ capabilities:
- A fixed Hazard3 management core owns system control and has a permanent JTAG
Debug Module.
- The C0-C5 extension fabric permits one selected user core to run at a time.
- The C0-C3 extension fabric permits one selected user core to run at a time.
- SYSCTRL controls user-core selection, reset, interrupt admission, and bus
admission. A stop request blocks new user transactions, drains an accepted
transaction, and then asserts reset.
+3 -3
View File
@@ -1,8 +1,8 @@
# PDK-specific Liberty inputs for the reproducible core-STA baseline.
ifeq ($(PDK),IHP130)
OPENSTA_LIBERTY := $(ROOT_PATH)/physical/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_stdcell/lib/sg13g2_stdcell_slow_1p08V_125C.lib
OPENSTA_LINK_LIBS := $(ROOT_PATH)/physical/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_io/lib/sg13g2_io_slow_1p08V_3p0V_125C.lib
OPENSTA_LIBERTY := $(ROOT_PATH)/physical/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_stdcell/lib/sg13g2_stdcell_slow_1p08V_125C.lib
OPENSTA_LINK_LIBS := $(ROOT_PATH)/physical/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_io/lib/sg13g2_io_slow_1p08V_3p0V_125C.lib
IHP130_USB2_SRAM_LIBS := \
$(ROOT_PATH)/physical/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_sram/lib/RM_IHPSG13_1P_4096x16_c3_bm_bist_slow_1p08V_125C.lib \
$(ROOT_PATH)/physical/pdk/IHP-Open-PDK/ihp-sg13g2/libs.ref/sg13g2_sram/lib/RM_IHPSG13_1P_4096x8_c3_bm_bist_slow_1p08V_125C.lib
@@ -24,4 +24,4 @@ else
$(error OpenSTA core-STA does not support PDK=$(PDK))
endif
OPENSTA_SRAM_LIBS ?=
OPENSTA_SRAM_LIBS ?=
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -11,7 +11,7 @@
"signature": "56c5f69398be8d7b"
},
{
"count": 10,
"count": 13,
"example": "warning:The network is combinational (run \"fraig\" or \"fraig_sweep\").",
"signature": "62cc5ee554312205"
},
File diff suppressed because it is too large. Load diff
+3 -1
View File
@@ -5,6 +5,8 @@ ordinary self-owned IP workflow.
- clusterip contains repositories locked by dependencies/dependencies.lock.json.
- mpw contains the locked Mini-ver-MPW generator and its prepared core inputs.
KianV RV32IMA and PicoRV32 remain available as managed sources but are
omitted by the active retroSoC user-extension map.
- third_party contains the locked external IP repository.
- picorv32 contains the repository-vendored PicoRV32 source and its
flow-generated picorv32_ver.v derivative.
@@ -12,4 +14,4 @@ ordinary self-owned IP workflow.
Use the top-level setup targets to update locked inputs. Do not edit MPW output
or locked checkouts in place. The PicoRV32 derivative is regenerated by the
setup-core target from the vendored source and preserves the project macro
contract used by the active filelist.
contract if the core is re-enabled.
+1 -1
View File
@@ -53,7 +53,7 @@ $(MPW_STAMP):
@mkdir -p $(@D)
@touch $@
$(MPW_VARIANT_STAMP): $(MPW_STAMP) $(ROOT_PATH)/scripts/generate_mpw.py
$(MPW_VARIANT_STAMP): $(MPW_STAMP) $(USER_EXTENSIONS_SOURCE) $(ROOT_PATH)/scripts/generate_mpw.py
$(FLOW_PYTHON) $(ROOT_PATH)/scripts/generate_mpw.py --root $(ROOT_PATH) \
--output $(MPW_OUTPUT_DIR) \
--lock-file $(CACHE_ROOT)/locks/mpw.lock
+5 -4
View File
@@ -52,10 +52,11 @@ core IRQ bit unallocated and driven low. Firmware does not
expose a generic external interrupt API until the SoC includes a claim/complete
interrupt controller.
`user_extensions.json` defines the SoC-level user-core and user-IP slots.
The locked mini-ver-mpw `mpw.toml` remains the source of truth for enabled
design IDs, module names, slots, and reset type. `scripts/generate_mpw.py`
verifies that both descriptions agree before RTL generation.
`user_extensions.json` defines the active SoC-level user-core and user-IP
design IDs, slots, module names, and reset types. The locked mini-ver-mpw
`mpw.toml` remains the source of truth for available design metadata and source
locations. `scripts/generate_mpw.py` selects and renumbers the configured
designs, then verifies the generated manifest before RTL generation.
`generate_user_extensions.py` then creates isolated default routing and one
explicit instance per selected slot for `user_core_top.sv` and `user_ip_top.sv`.
User cores keep `ribp_if.master ribp` at the extension ABI and are converted to
@@ -20,6 +20,7 @@ APB_REQUEST_SIGNALS = ("paddr", "pprot", "psel", "penable", "pwrite", "pwdata",
@dataclass(frozen=True)
class ExtensionTarget:
slot: int
design_id: str
module: str
instance: str
bus: str
@@ -74,12 +75,14 @@ def parse_targets(
raise ValueError(f"{field} must be a non-empty list")
targets: list[ExtensionTarget] = []
slots: set[int] = set()
design_ids: set[str] = set()
instances: set[str] = set()
for index, entry in enumerate(value):
target = require_object(entry, f"{field}[{index}]")
slot = target.get("slot")
if not isinstance(slot, int) or not first_slot <= slot < (1 << selector_width):
raise ValueError(f"{field}[{index}].slot must be within the selector range")
design_id = require_identifier(target.get("design_id"), f"{field}[{index}].design_id")
module = require_identifier(target.get("module"), f"{field}[{index}].module")
instance = require_identifier(target.get("instance"), f"{field}[{index}].instance")
if field == "core_targets":
@@ -94,11 +97,14 @@ def parse_targets(
reset = "async"
if slot in slots:
raise ValueError(f"{field} slot {slot} is duplicated")
if design_id in design_ids:
raise ValueError(f"{field} design_id {design_id} is duplicated")
if instance in instances:
raise ValueError(f"{field} instance {instance} is duplicated")
slots.add(slot)
design_ids.add(design_id)
instances.add(instance)
targets.append(ExtensionTarget(slot, module, instance, bus, reset))
targets.append(ExtensionTarget(slot, design_id, module, instance, bus, reset))
ordered = tuple(sorted(targets, key=lambda item: item.slot))
if [target.slot for target in ordered] != list(range(first_slot, first_slot + len(ordered))):
raise ValueError(f"{field} slots must be contiguous from {first_slot}")
@@ -107,8 +113,8 @@ def parse_targets(
def read_extensions(path: Path) -> ExtensionMap:
document = require_object(json.loads(path.read_text(encoding="utf-8")), "user extensions")
if document.get("schema_version") != 1:
raise ValueError("schema_version must be 1")
if document.get("schema_version") != 2:
raise ValueError("schema_version must be 2")
core_selector_width = require_positive_integer(
document.get("core_selector_width"), "core_selector_width"
)
+7 -9
View File
@@ -1,18 +1,16 @@
{
"schema_version": 1,
"schema_version": 2,
"core_selector_width": 5,
"ip_selector_width": 8,
"gpio_width": 32,
"core_targets": [
{"slot": 0, "module": "mpw_c0", "instance": "u_mpw_core_kianv_rv32i", "bus": "ribp", "reset": "sync"},
{"slot": 1, "module": "mpw_c1", "instance": "u_mpw_core_kianv_rv32ima", "bus": "ribp", "reset": "sync"},
{"slot": 2, "module": "mpw_c2", "instance": "u_mpw_core_serv", "bus": "ribp", "reset": "async"},
{"slot": 3, "module": "mpw_c3", "instance": "u_mpw_core_femtorv32", "bus": "ribp", "reset": "async"},
{"slot": 4, "module": "mpw_c4", "instance": "u_mpw_core_darkriscv", "bus": "ribp", "reset": "async"},
{"slot": 5, "module": "mpw_c5", "instance": "u_mpw_core_picorv32", "bus": "ribp", "reset": "sync"}
{"slot": 0, "design_id": "kianv_rv32i", "module": "mpw_c0", "instance": "u_mpw_core_kianv_rv32i", "bus": "ribp", "reset": "sync"},
{"slot": 1, "design_id": "serv", "module": "mpw_c1", "instance": "u_mpw_core_serv", "bus": "ribp", "reset": "async"},
{"slot": 2, "design_id": "femtorv32", "module": "mpw_c2", "instance": "u_mpw_core_femtorv32", "bus": "ribp", "reset": "async"},
{"slot": 3, "design_id": "darkriscv", "module": "mpw_c3", "instance": "u_mpw_core_darkriscv", "bus": "ribp", "reset": "async"}
],
"ip_targets": [
{"slot": 1, "module": "mpw_i1", "instance": "u_mpw_ip_tiny_timer"},
{"slot": 2, "module": "mpw_i2", "instance": "u_mpw_ip_tiny_gpio"}
{"slot": 1, "design_id": "tiny_timer", "module": "mpw_i1", "instance": "u_mpw_ip_tiny_timer"},
{"slot": 2, "design_id": "tiny_gpio", "module": "mpw_i2", "instance": "u_mpw_ip_tiny_gpio"}
]
}
+1 -1
View File
@@ -215,4 +215,4 @@ firmware: $(FIRMWARE_ELF)
firmware asm: | manifest
.PHONY: FORCE_VERSION
.PHONY: FORCE_VERSION
+114 -11
View File
@@ -6,27 +6,126 @@ from __future__ import annotations
import argparse
import fcntl
import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path
from typing import Any
try:
import tomllib
except ModuleNotFoundError: # Python 3.10
import tomli as tomllib
def toml_value(value: object) -> str:
if isinstance(value, bool):
return "true" if value else "false"
if isinstance(value, int):
return str(value)
if isinstance(value, str):
return json.dumps(value, ensure_ascii=True)
if isinstance(value, list) and all(isinstance(item, str) for item in value):
return "[" + ", ".join(json.dumps(item, ensure_ascii=True) for item in value) + "]"
raise ValueError(f"unsupported MPW manifest value: {value!r}")
def render_active_manifest(manifest_path: Path, extensions_path: Path) -> str:
"""Select and renumber locked MPW designs from the self-owned extension map."""
document = tomllib.loads(manifest_path.read_text(encoding="utf-8"))
if document.get("schema_version") != 2:
raise ValueError(f"{manifest_path}: schema_version must be 2")
generator = document.get("generator")
if not isinstance(generator, dict):
raise ValueError(f"{manifest_path}: generator must be a table")
designs = document.get("design")
if not isinstance(designs, list):
raise ValueError(f"{manifest_path}: design must be an array")
available: dict[tuple[str, str], dict[str, Any]] = {}
for design in designs:
if not isinstance(design, dict):
raise ValueError(f"{manifest_path}: design contains a non-table entry")
key = (design.get("kind"), design.get("id"))
if not all(isinstance(item, str) for item in key):
raise ValueError(f"{manifest_path}: every design requires string kind and id")
if key in available:
raise ValueError(f"{manifest_path}: duplicate {key[0]} design id {key[1]}")
available[key] = design
extensions = json.loads(extensions_path.read_text(encoding="utf-8"))
if not isinstance(extensions, dict) or extensions.get("schema_version") != 2:
raise ValueError(f"{extensions_path}: schema_version must be 2")
selected: list[dict[str, Any]] = []
selected_ids: set[tuple[str, str]] = set()
for kind, target_key in (("core", "core_targets"), ("ip", "ip_targets")):
targets = extensions.get(target_key)
if not isinstance(targets, list):
raise ValueError(f"{extensions_path}: {target_key} must be a list")
for index, target in enumerate(targets):
if not isinstance(target, dict):
raise ValueError(f"{extensions_path}: {target_key}[{index}] must be an object")
design_id = target.get("design_id")
slot = target.get("slot")
key = (kind, design_id)
if not isinstance(design_id, str) or key not in available:
raise ValueError(
f"{extensions_path}: {target_key}[{index}] selects unknown {kind} design {design_id!r}"
)
if key in selected_ids:
raise ValueError(f"{extensions_path}: {kind} design {design_id} is selected more than once")
if not isinstance(slot, int) or slot < 0:
raise ValueError(f"{extensions_path}: {target_key}[{index}].slot must be non-negative")
expected_module = f"mpw_{kind[0]}{slot}"
if target.get("module") != expected_module:
raise ValueError(
f"{extensions_path}: {target_key}[{index}].module must be {expected_module}"
)
design = dict(available[key])
if kind == "core" and target.get("reset") != design.get("reset"):
raise ValueError(
f"{extensions_path}: {target_key}[{index}].reset does not match {design_id}"
)
design["slot"] = slot
design.pop("enabled", None)
selected.append(design)
selected_ids.add(key)
lines = [f"schema_version = {document['schema_version']}", "", "[generator]"]
lines.extend(f"{key} = {toml_value(value)}" for key, value in generator.items())
for design in selected:
lines.extend(["", "[[design]]"])
lines.extend(f"{key} = {toml_value(value)}" for key, value in design.items())
return "\n".join(lines) + "\n"
def generate(root: Path, output: Path) -> None:
managed_mpw = root / "rtl/managed/mpw"
manifest = managed_mpw / "mpw.toml"
extensions = root / "rtl/mini/integration/user_extensions.json"
if not manifest.is_file():
raise FileNotFoundError(f"MPW v2 manifest is missing: {manifest}")
command = [
sys.executable,
"-m",
"mpwgen",
"generate",
"--manifest",
str(manifest),
"--output",
str(output),
]
subprocess.run(command, cwd=managed_mpw, check=True)
descriptor, manifest_name = tempfile.mkstemp(
prefix=".retrosoc-active-", suffix=".toml", dir=managed_mpw
)
active_manifest = Path(manifest_name)
try:
with os.fdopen(descriptor, "w", encoding="utf-8", newline="\n") as stream:
stream.write(render_active_manifest(manifest, extensions))
command = [
sys.executable,
"-m",
"mpwgen",
"generate",
"--manifest",
str(active_manifest),
"--output",
str(output),
]
subprocess.run(command, cwd=managed_mpw, check=True)
finally:
active_manifest.unlink(missing_ok=True)
validate_extension_bindings(root, output)
@@ -63,6 +162,10 @@ def validate_extension_bindings(root: Path, output: Path) -> None:
raise ValueError(f"{extensions_path}: {target_key} slots do not match MPW v2")
for slot, design in expected.items():
target = actual[slot]
if target.get("design_id") != design.get("id"):
raise ValueError(
f"{extensions_path}: {kind} slot {slot} design ID does not match MPW v2"
)
if target.get("module") != design.get("top"):
raise ValueError(
f"{extensions_path}: {kind} slot {slot} does not match {design.get('top')}"
+4 -4
View File
@@ -155,20 +155,20 @@ module sysctrl_tb;
if (read_data !== 32'd151) $fatal(1, "USB2 performance snapshot was not recorded");
read_register(32'h1000_B020, read_data);
if (read_data !== 32'h0000_003F) $fatal(1, "user cores were not held in reset");
write_register(32'h1000_B000, 32'h0000_0006);
if (read_data !== 32'h0000_000F) $fatal(1, "user cores were not held in reset");
write_register(32'h1000_B000, 32'h0000_0004);
read_register(32'h1000_B024, read_data);
if ((read_data & 32'h0000_083F) !== 32'h0000_0800) begin
$fatal(1, "out-of-range user core selection was accepted");
end
write_register(32'h1000_B024, 32'h0000_0800);
write_register(32'h1000_B000, 32'h0000_0001);
write_register(32'h1000_B020, 32'h0000_003D);
write_register(32'h1000_B020, 32'h0000_000D);
read_register(32'h1000_B024, read_data);
if ((read_data & 32'h0000_0300) !== 32'h0000_0300 || (read_data & 32'h1F) != 1) begin
$fatal(1, "user core start state was not recorded");
end
write_register(32'h1000_B020, 32'h0000_003F);
write_register(32'h1000_B020, 32'h0000_000F);
read_register(32'h1000_B024, read_data);
if ((read_data & 32'h0000_0300) !== 32'h0000_0200) begin
$fatal(1, "user core stop state was not recorded");
+11 -1
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import os
import re
import shutil
import subprocess
@@ -46,6 +47,13 @@ def test_opipsram_protocol_model_compiles_and_runs() -> None:
work = ROOT / ".cache" / "test-opipsram"
shutil.rmtree(work, ignore_errors=True)
work.mkdir(parents=True, exist_ok=True)
ccache_dir = work / "ccache"
ccache_tmp = work / "ccache-tmp"
ccache_dir.mkdir()
ccache_tmp.mkdir()
environment = os.environ.copy()
environment["CCACHE_DIR"] = str(ccache_dir)
environment["CCACHE_TEMPDIR"] = str(ccache_tmp)
output = work / "opipsram_tb"
sources = [
ROOT / "rtl/managed/clusterip/common/rtl/interface/axi4_if.sv",
@@ -93,7 +101,9 @@ def test_opipsram_protocol_model_compiles_and_runs() -> None:
str(output),
]
try:
compile_result = subprocess.run(command, check=False, text=True, capture_output=True)
compile_result = subprocess.run(
command, check=False, text=True, capture_output=True, env=environment
)
if compile_result.returncode != 0:
pytest.fail(
"production OPI PSRAM RTL does not compile with the locked model list:\n"
+79 -6
View File
@@ -38,7 +38,7 @@ from scripts.development_environment import ( # noqa: E402
render_activation,
stamp_data,
)
from scripts.generate_mpw import validate_extension_bindings # noqa: E402
from scripts.generate_mpw import render_active_manifest, validate_extension_bindings # noqa: E402
from scripts.install_toolchain import safe_extract # noqa: E402
from scripts.package import make_sbom # noqa: E402
from scripts import regress # noqa: E402
@@ -395,7 +395,69 @@ def test_mpw_generator_uses_only_the_native_v2_contract() -> None:
assert "migrate_user_" not in source
assert "prepare_legacy_mpw_workspace" not in source
assert '"-m",\n "mpwgen"' in source
assert '"mpwgen"' in source
assert '"generate"' in source
def test_mpw_active_manifest_uses_self_owned_design_selection(tmp_path: Path) -> None:
manifest = tmp_path / "mpw.toml"
manifest.write_text(
"""schema_version = 2
[generator]
api_version = "retrosoc-mpw-v2"
[[design]]
kind = "core"
id = "slow_core"
slot = 0
enabled = false
source_dir = "core/slow"
top = "user_core_design"
filelist = "usercore.fl"
reset = "sync"
name = "Slow"
isa = "rv32i"
maintainer = "owner"
repo = "https://example.com/slow"
[[design]]
kind = "core"
id = "selected_core"
slot = 5
source_dir = "core/selected"
top = "user_core_design"
filelist = "usercore.fl"
reset = "async"
name = "Selected"
isa = "rv32i"
maintainer = "owner"
repo = "https://example.com/selected"
""",
encoding="utf-8",
)
extensions = tmp_path / "user_extensions.json"
extensions.write_text(
json.dumps(
{
"schema_version": 2,
"core_targets": [
{
"slot": 0,
"design_id": "selected_core",
"module": "mpw_c0",
"reset": "async",
}
],
"ip_targets": [],
}
),
encoding="utf-8",
)
active = render_active_manifest(manifest, extensions)
assert 'id = "selected_core"' in active
assert 'id = "slow_core"' not in active
assert "slot = 0" in active
assert "enabled" not in active
def test_mpw_extension_bindings_match_generated_manifest(tmp_path: Path) -> None:
@@ -403,10 +465,15 @@ def test_mpw_extension_bindings_match_generated_manifest(tmp_path: Path) -> None
extensions_path.parent.mkdir(parents=True)
extensions = {
"core_targets": [
{"slot": 0, "module": "mpw_core_zero", "reset": "sync"},
{
"slot": 0,
"design_id": "core_zero",
"module": "mpw_core_zero",
"reset": "sync",
},
],
"ip_targets": [
{"slot": 1, "module": "mpw_ip_one"},
{"slot": 1, "design_id": "ip_one", "module": "mpw_ip_one"},
],
}
extensions_path.write_text(json.dumps(extensions), encoding="utf-8")
@@ -414,8 +481,14 @@ def test_mpw_extension_bindings_match_generated_manifest(tmp_path: Path) -> None
output.mkdir()
manifest = {
"designs": [
{"kind": "core", "slot": 0, "top": "mpw_core_zero", "reset": "sync"},
{"kind": "ip", "slot": 1, "top": "mpw_ip_one"},
{
"kind": "core",
"id": "core_zero",
"slot": 0,
"top": "mpw_core_zero",
"reset": "sync",
},
{"kind": "ip", "id": "ip_one", "slot": 1, "top": "mpw_ip_one"},
]
}
(output / "manifest.json").write_text(json.dumps(manifest), encoding="utf-8")
+20 -8
View File
@@ -49,18 +49,22 @@ def test_extensions_generate_isolated_scalar_bindings(tmp_path: Path) -> None:
filelist = (tmp_path / "user_extensions.fl").read_text(encoding="utf-8")
config = (tmp_path / "rtl/user_extensions_config.svh").read_text(encoding="utf-8")
assert core.count("rib_if u_user_") == 6
assert core.count("ribp_if u_user_") == 6
assert core.count("ribp2rib #(") == 6
assert core.count(".SyncReset(1'b1)") == 3
assert core.count("rib_if u_user_") == 4
assert core.count("ribp_if u_user_") == 4
assert core.count("ribp2rib #(") == 4
assert core.count(".SyncReset(1'b1)") == 1
assert core.count(".SyncReset(1'b0)") == 3
assert "u_user_rib_if.cmd_valid = '0;" in core
assert "5'd0: begin" in core
assert "5'd4: begin" in core
assert "5'd5: begin" in core
assert "5'd3: begin" in core
assert "5'd4: begin" not in core
assert "core_reset_i[0]" in core
assert "mpw_c0 #(0)" in core
assert "mpw_c5 #(5)" in core
assert "mpw_c1 #(1)" in core
assert "mpw_c3 #(3)" in core
assert "u_mpw_core_serv" in core
assert "u_mpw_core_kianv_rv32ima" not in core
assert "u_mpw_core_picorv32" not in core
assert "mpw_i1 #(1)" in ip
assert "User core 0 uses the RIBP contract" in core
assert ip.count("user_gpio_if #(`USER_GPIO_NUM)") == 2
@@ -68,7 +72,7 @@ def test_extensions_generate_isolated_scalar_bindings(tmp_path: Path) -> None:
assert "8'd2: begin" in ip
assert "u_user_2_apb4_if.psel = apb.psel;" in ip
assert filelist.startswith("+incdir+")
assert "`define USER_CORE_COUNT 6" in config
assert "`define USER_CORE_COUNT 4" in config
def test_extensions_reject_noncontiguous_slots_and_invalid_modules(tmp_path: Path) -> None:
@@ -91,3 +95,11 @@ def test_extensions_reject_invalid_core_reset_style(tmp_path: Path) -> None:
result = validate(write_invalid_extensions(tmp_path, document))
assert result.returncode != 0
assert ".reset must be sync or async" in result.stderr
def test_extensions_reject_duplicate_design_selection(tmp_path: Path) -> None:
document = json.loads(EXTENSIONS.read_text(encoding="utf-8"))
document["core_targets"][1]["design_id"] = document["core_targets"][0]["design_id"]
result = validate(write_invalid_extensions(tmp_path, document))
assert result.returncode != 0
assert "design_id kianv_rv32i is duplicated" in result.stderr