mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
Merge branch 'dev' into feat/mini-hp-core
This commit is contained in:
178 files changed
+19273
-1442
No files matched your search
@@ -132,7 +132,7 @@ jobs:
|
||||
|
||||
- name: Upload reports and structured results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: ${{ inputs.suite }}-regression-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: |
|
||||
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
|
||||
- name: Upload reports and structured results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: environment-${{ matrix.environment }}-ihp130-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: |
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
run: make CONFIG=configs/ci/ihp130.mk package
|
||||
|
||||
- name: Upload workflow artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: retrosoc-${{ github.ref_name }}
|
||||
path: dist/**
|
||||
|
||||
@@ -56,7 +56,7 @@ JTAG_IDCODE ?= DEADBEEF
|
||||
EXT_CLK_HZ ?= 72000000
|
||||
AUD_CLK_HZ ?= 18432000
|
||||
CLINT_TIMEBASE_HZ ?= 1000000
|
||||
MGMT_CPU_CLK_HZ := $(if $(filter PRODUCT,$(MINI_MODE)),24000000,$(EXT_CLK_HZ))
|
||||
MGMT_CPU_CLK_HZ := $(if $(filter TINY,$(SOC)),24000000,$(if $(filter PRODUCT,$(MINI_MODE)),24000000,$(EXT_CLK_HZ)))
|
||||
# Reset-state peripheral clock: the PCLK divider in the clock/reset subsystem
|
||||
# resets to passthrough on the LP root clock, so PCLK starts at the management
|
||||
# CPU frequency until software programs a different divider.
|
||||
@@ -84,6 +84,7 @@ SW_ISA_PROFILE ?= COMPAT
|
||||
SW_OPT ?= APP
|
||||
SW_LTO ?= NO
|
||||
WS2812_P3_ACCEPTANCE ?= NO
|
||||
TINY_P7_ACCEPTANCE ?= NO
|
||||
COREMARK_MODE ?= quick
|
||||
NPU_P5_ACCEPTANCE ?= NO
|
||||
# Select the HP (OpenC906) JTAG target before the LP releases it; debug aid
|
||||
@@ -132,6 +133,9 @@ endif
|
||||
ifeq ($(WS2812_P3_ACCEPTANCE),YES)
|
||||
CONFIG_KEY_VARS += WS2812_P3_ACCEPTANCE
|
||||
endif
|
||||
ifeq ($(TINY_P7_ACCEPTANCE),YES)
|
||||
CONFIG_KEY_VARS += TINY_P7_ACCEPTANCE
|
||||
endif
|
||||
VARIANT_ID := $(strip $(shell $(VCS_SHELL_PYTHON) $(ROOT_PATH)/scripts/config_key.py \
|
||||
--lock $(LOCK_FILE) --profile $(PROFILE_NAME) --timestamp $(BUILD_TIMESTAMP) \
|
||||
$(foreach var,$(CONFIG_KEY_VARS),--value $(var)=$($(var))) | tail -n 1))
|
||||
@@ -291,6 +295,12 @@ $(call validate_value,SW_ISA_PROFILE,COMPAT TINY_PERF)
|
||||
$(call validate_value,SW_OPT,APP O2 O3 Os)
|
||||
$(call validate_value,SW_LTO,$(VALID_BOOL))
|
||||
$(call validate_value,WS2812_P3_ACCEPTANCE,$(VALID_BOOL))
|
||||
$(call validate_value,TINY_P7_ACCEPTANCE,$(VALID_BOOL))
|
||||
ifeq ($(TINY_P7_ACCEPTANCE),YES)
|
||||
ifneq ($(SOC)/$(APP)/$(HAVE_CSR),TINY/ci_smoke/YES)
|
||||
$(error TINY_P7_ACCEPTANCE requires SOC=TINY APP=ci_smoke HAVE_CSR=YES)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(WS2812_P3_ACCEPTANCE),YES)
|
||||
ifneq ($(SOC)/$(APP)/$(HAVE_CSR),MINI/ci_smoke/YES)
|
||||
$(error WS2812_P3_ACCEPTANCE requires SOC=MINI APP=ci_smoke HAVE_CSR=YES)
|
||||
@@ -387,7 +397,7 @@ endif
|
||||
|
||||
ifeq ($(STA),OPENSTA)
|
||||
ifeq ($(HAVE_PLL),YES)
|
||||
ifneq ($(SOC)/$(PDK)/$(TINY_SAFE24_PLL_OFF),TINY/ICS55/YES)
|
||||
ifneq ($(SOC)/$(PDK)/$(TINY_R2_P7),TINY/ICS55/YES)
|
||||
$(error STA=OPENSTA requires a qualified PDK PLL timing profile; HAVE_PLL=YES is unsupported)
|
||||
endif
|
||||
endif
|
||||
@@ -424,6 +434,8 @@ endif
|
||||
|
||||
ifeq ($(HAVE_SVA), NO)
|
||||
DEF_LIST += +define+SV_ASSRT_DISABLE
|
||||
else ifeq ($(SOC),TINY)
|
||||
DEF_LIST += +define+HAVE_SVA
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_HP), YES)
|
||||
|
||||
@@ -138,8 +138,10 @@ points, not the complete profile or application inventory.
|
||||
|
||||
Tiny's [2026-10-07 target refreeze](docs/ip/tiny-soc.md#ics55-default-platform-and-final-timing-gate-2026-10-07)
|
||||
selects ICS55 with `HAVE_PLL=YES` and SAFE24 startup as the default.
|
||||
The profile instantiates a parked PLL; dynamic SYS switching remains R2-P7 and
|
||||
physical qualification is pending. IHP130 remains explicit compatibility.
|
||||
The PLL starts parked off. The [R2-P7 implementation](docs/ip/tiny-soc-r2-clock-reset.md)
|
||||
adds software-controlled SYS transitions; acceptance evidence is tracked in
|
||||
the Tiny ledger and physical qualification remains pending. IHP130 remains
|
||||
explicit compatibility.
|
||||
Locked PLL views can be acquired
|
||||
with `python3 physical/pdk/setup.py --pdk ICS55 --component pll` independently
|
||||
of platform implementation or timing qualification.
|
||||
|
||||
+6
-2
@@ -176,7 +176,11 @@ configurations, and build artifact locations.
|
||||
|
||||
For `SOC=TINY`, `bringup` and `ci_smoke` use the MCU acceptance composition. It
|
||||
boots through XPI into SRAM, checks CPU C/A behavior and bus exceptions, DMA
|
||||
(including UART requests), interrupts, RTC, GPIO, UART1 and I2C error completion,
|
||||
then verifies watchdog reset by completing after the next NOR boot. It uses
|
||||
(including UART requests), interrupts, RTC, GPIO and I2C0 error completion.
|
||||
The P6 composition additionally checks RNG qualification rejection, CRC DMA,
|
||||
Crypto initialization/vectors/erasure, audio plus finite WS refill and background
|
||||
DMA, and SDIO transfers/recovery with verification-board models. Missing external
|
||||
devices fail boundedly; they do not hold CPU boot reset. The image then verifies
|
||||
watchdog reset by completing after the next NOR boot. It uses
|
||||
SYSCTRL terminal status. The small `asm/tiny_boot.S` image separately qualifies
|
||||
the synthesized SRAM/pad path; it is not a replacement for the full RTL test.
|
||||
@@ -1,3 +1,4 @@
|
||||
APP_SRCS += $(ROOT_PATH)/app/apps/ci_smoke/tiny.c
|
||||
APP_CFLAGS += -Os
|
||||
APP_SRCS += $(ROOT_PATH)/app/apps/ci_smoke/mcu_acceptance.S
|
||||
APP_SRCS += $(ROOT_PATH)/app/apps/ci_smoke/tiny_r2_p6.c
|
||||
@@ -34,3 +34,15 @@ rs_mcu_unmapped_probe:
|
||||
.option pop
|
||||
ret
|
||||
.size rs_mcu_unmapped_probe, .-rs_mcu_unmapped_probe
|
||||
|
||||
.balign 4
|
||||
.global rs_mcu_execute_probe
|
||||
.type rs_mcu_execute_probe,@function
|
||||
rs_mcu_execute_probe:
|
||||
mv t0, a0
|
||||
.option push
|
||||
.option arch, +zifencei
|
||||
fence.i
|
||||
.option pop
|
||||
jr t0
|
||||
.size rs_mcu_execute_probe, .-rs_mcu_execute_probe
|
||||
@@ -6,5 +6,6 @@
|
||||
uint32_t rs_mcu_compressed_probe(void);
|
||||
void rs_mcu_atomic_probe(uint32_t *address);
|
||||
void rs_mcu_unmapped_probe(void);
|
||||
uint32_t rs_mcu_execute_probe(uint32_t address);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef RETROSOC_APP_MCU_SHARED_ACCEPTANCE_H
|
||||
#define RETROSOC_APP_MCU_SHARED_ACCEPTANCE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Zero means every P6 acceptance case completed; other values identify failure. */
|
||||
uint8_t rs_tiny_p6_acceptance(void);
|
||||
|
||||
#endif
|
||||
+73
-36
@@ -12,6 +12,7 @@
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
#include <retrosoc/hal/onchip_sram.h>
|
||||
#include <retrosoc/hal/pwm.h>
|
||||
#include <retrosoc/hal/rcu.h>
|
||||
#include <retrosoc/hal/rtc.h>
|
||||
#include <retrosoc/hal/sysctrl.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
@@ -20,12 +21,16 @@
|
||||
#include <retrosoc/lib/printf.h>
|
||||
|
||||
#include "mcu_acceptance.h"
|
||||
#include "mcu_shared_acceptance.h"
|
||||
|
||||
static _Alignas(64) uint32_t rs_mcu_source[80];
|
||||
static _Alignas(64) uint32_t rs_mcu_destination[80];
|
||||
static volatile uint32_t rs_mcu_irq_count;
|
||||
static volatile uint32_t rs_mcu_exception_count;
|
||||
static volatile bool rs_mcu_handler_failed;
|
||||
static volatile bool rs_mcu_probes_active;
|
||||
static uint8_t rs_mcu_io_code;
|
||||
static volatile uint32_t rs_mcu_watchdog_cookie __attribute__((section(".noinit.rs_mcu_wdg")));
|
||||
|
||||
static void rs_mcu_finish(bool pass, uint8_t code) {
|
||||
printf("Tiny acceptance %s code=%u\n", pass ? "passed" : "failed", code);
|
||||
@@ -39,8 +44,8 @@ static void rs_mcu_finish(bool pass, uint8_t code) {
|
||||
static void rs_mcu_exception(uintptr_t mcause, uintptr_t stack_pointer) {
|
||||
volatile uint32_t *const frame = (volatile uint32_t *)stack_pointer;
|
||||
|
||||
if ((mcause != UINT32_C(2)) && (mcause != UINT32_C(5))) {
|
||||
rs_mcu_handler_failed = true;
|
||||
if (!rs_mcu_probes_active || ((mcause != UINT32_C(2)) && (mcause != UINT32_C(5)))) {
|
||||
rs_mcu_finish(false, 11U);
|
||||
}
|
||||
++rs_mcu_exception_count;
|
||||
/* system_irq.S saves MEPC in slot 11 of the RV32 trap frame. Both test
|
||||
@@ -75,7 +80,7 @@ static bool rs_mcu_dma(void) {
|
||||
rs_mcu_source[index] = UINT32_C(0xa519c300) ^ index;
|
||||
rs_mcu_destination[index] = UINT32_C(0xcccccccc);
|
||||
}
|
||||
if ((rs_dma_configure(4U, &config) != RS_EINVAL) ||
|
||||
if ((rs_dma_configure(8U, &config) != RS_EINVAL) ||
|
||||
(rs_dma_configure(RS_DMA_CHANNEL_BULK, &config) != RS_OK) ||
|
||||
(rs_dma_start(RS_DMA_CHANNEL_BULK) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_BULK, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
@@ -91,8 +96,26 @@ static bool rs_mcu_dma(void) {
|
||||
return false;
|
||||
}
|
||||
config.kind = RS_DMA_KIND_MM_TO_STREAM;
|
||||
config.request = RS_DMA_REQUEST_I2S_TX;
|
||||
return rs_dma_config_validate(0U, &config) != RS_OK;
|
||||
config.request = RS_DMA_REQUEST_DVP_RX;
|
||||
if (rs_dma_config_validate(0U, &config) == RS_OK) {
|
||||
return false;
|
||||
}
|
||||
/* DMA owns the destination until completion. FENCE.I is executed by the
|
||||
* assembly helper before entering either the DMA-written or patched code. */
|
||||
rs_mcu_source[0] = UINT32_C(0x02a00513); /* addi a0,zero,42 */
|
||||
rs_mcu_source[1] = UINT32_C(0x00008067); /* jalr zero,ra,0 */
|
||||
config.kind = RS_DMA_KIND_MM_TO_MM;
|
||||
config.request = RS_DMA_REQUEST_SOFTWARE;
|
||||
config.byte_count = UINT32_C(8);
|
||||
config.burst_beats = 1U;
|
||||
if ((rs_dma_configure(RS_DMA_CHANNEL_BULK, &config) != RS_OK) ||
|
||||
(rs_dma_start(RS_DMA_CHANNEL_BULK) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_BULK, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_mcu_execute_probe((uint32_t)(uintptr_t)rs_mcu_destination) != UINT32_C(42))) {
|
||||
return false;
|
||||
}
|
||||
rs_mcu_destination[0] = UINT32_C(0x02b00513); /* addi a0,zero,43 */
|
||||
return rs_mcu_execute_probe((uint32_t)(uintptr_t)rs_mcu_destination) == UINT32_C(43);
|
||||
}
|
||||
|
||||
static bool rs_mcu_interrupts(void) {
|
||||
@@ -146,9 +169,7 @@ static bool rs_mcu_io(void) {
|
||||
const uint32_t transmit[4] = {UINT32_C(0x54), UINT32_C(0x49), UINT32_C(0x4e), UINT32_C(0x59)};
|
||||
uint32_t receive[4] = {0U};
|
||||
rs_gpio_capabilities_t capabilities;
|
||||
rs_uart_timing_t timing;
|
||||
bool high;
|
||||
uint32_t timeout = UINT32_C(10000);
|
||||
uint8_t payload = UINT8_C(0x55);
|
||||
const rs_i2c_transfer_t transfer = {
|
||||
.address = UINT16_C(0x50),
|
||||
@@ -157,54 +178,51 @@ static bool rs_mcu_io(void) {
|
||||
};
|
||||
rs_i2c_status_t status;
|
||||
|
||||
rs_mcu_io_code = 40U;
|
||||
if ((rs_gpio_get_capabilities(&capabilities) != RS_OK) ||
|
||||
((capabilities.pad_features & (RS_GPIO_PAD_CAP_PULL_UP | RS_GPIO_PAD_CAP_PULL_DOWN)) !=
|
||||
((RS_SOC_GPIO_HAS_PULLS != 0U) ? (RS_GPIO_PAD_CAP_PULL_UP | RS_GPIO_PAD_CAP_PULL_DOWN)
|
||||
: 0U)) ||
|
||||
(rs_gpio_configure(15U, &pull_up) !=
|
||||
(rs_gpio_configure(27U, &pull_up) !=
|
||||
((RS_SOC_GPIO_HAS_PULLS != 0U) ? RS_OK : RS_ENOTSUP)) ||
|
||||
(rs_gpio_configure(15U, &pull_down) !=
|
||||
(rs_gpio_configure(27U, &pull_down) !=
|
||||
((RS_SOC_GPIO_HAS_PULLS != 0U) ? RS_OK : RS_ENOTSUP)) ||
|
||||
(rs_gpio_configure(15U, &output) != RS_OK) || (rs_gpio_write(15U, true) != RS_OK) ||
|
||||
(rs_gpio_read(15U, &high) != RS_OK) || !high || (rs_gpio_write(15U, false) != RS_OK) ||
|
||||
(rs_gpio_read(15U, &high) != RS_OK) || high) {
|
||||
(rs_gpio_configure(27U, &output) != RS_OK) || (rs_gpio_write(27U, true) != RS_OK) ||
|
||||
(rs_gpio_read(27U, &high) != RS_OK) || !high || (rs_gpio_write(27U, false) != RS_OK) ||
|
||||
(rs_gpio_read(27U, &high) != RS_OK) || high) {
|
||||
return false;
|
||||
}
|
||||
rs_mcu_io_code = 41U;
|
||||
if ((rs_uart_configure(&loopback, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_uart_write_dma(transmit, 4U, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_uart_read_dma(receive, 4U, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
rs_mcu_io_code = 42U;
|
||||
for (uint32_t index = 0U; index < 4U; ++index) {
|
||||
if (transmit[index] != receive[index]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rs_mcu_io_code = 43U;
|
||||
if ((rs_uart_init(RS_CPU_CLOCK_HZ, UART_BPS) != RS_OK) ||
|
||||
(rs_uart_timing_calculate(RS_CPU_CLOCK_HZ, UART_BPS, &timing) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
/* UART1 uses the same register ABI; the current shared high-level UART
|
||||
* API selects UART0. Exercise UART1 PIO and its internal loopback here. */
|
||||
RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x00)) = timing.baud_integer;
|
||||
RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x04)) = timing.baud_fraction;
|
||||
RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x08)) = UINT32_C(3);
|
||||
RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x0c)) = UINT32_C(7);
|
||||
RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x10)) = UINT32_C(0x5a);
|
||||
while (((RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x18)) & UINT32_C(0x40)) != 0U) &&
|
||||
(timeout != 0U)) {
|
||||
--timeout;
|
||||
}
|
||||
if ((timeout == 0U) || ((RS_SOC_REG32(RS_SOC_APB4_UART1_BASE, UINT32_C(0x14)) &
|
||||
UINT32_C(0xff)) != UINT32_C(0x5a))) {
|
||||
(rs_i2c_init(RS_I2C_BUS_1, RS_CPU_CLOCK_HZ, UINT32_C(100000)) != RS_ENOTSUP)) {
|
||||
return false;
|
||||
}
|
||||
/* There is no slave on the pulled-up acceptance board: a real address
|
||||
* transaction must terminate as NACK rather than stick waiting on the bus. */
|
||||
for (uint32_t bus = 0U; bus < 2U; ++bus) {
|
||||
for (uint32_t bus = 0U; bus < 1U; ++bus) {
|
||||
rs_mcu_io_code = 44U;
|
||||
const rs_i2c_bus_t instance = (bus == 0U) ? RS_I2C_BUS_0 : RS_I2C_BUS_1;
|
||||
if ((rs_i2c_init(instance, RS_CPU_CLOCK_HZ, UINT32_C(100000)) != RS_OK) ||
|
||||
(rs_i2c_transfer(instance, &transfer, RS_TIMEOUT_DEFAULT) != RS_EIO) ||
|
||||
rs_status_t init_result = rs_i2c_init(instance, RS_CPU_CLOCK_HZ, UINT32_C(100000));
|
||||
rs_status_t transfer_result = init_result == RS_OK
|
||||
? rs_i2c_transfer(instance, &transfer, RS_TIMEOUT_DEFAULT)
|
||||
: init_result;
|
||||
printf("R2_P6_IO i2c_init=%d i2c_transfer=%d\n", (int)init_result, (int)transfer_result);
|
||||
if (rs_i2c_get_status(instance, &status) == RS_OK) {
|
||||
printf("R2_P6_IO i2c_errors=%lx\n", (unsigned long)status.errors);
|
||||
}
|
||||
if ((init_result != RS_OK) || (transfer_result != RS_EIO) ||
|
||||
(rs_i2c_get_status(instance, &status) != RS_OK) ||
|
||||
((status.errors & RS_I2C_ERROR_ADDR_NACK) == 0U)) {
|
||||
return false;
|
||||
@@ -235,8 +253,10 @@ int main(void) {
|
||||
rs_onchip_sram_info_t memory;
|
||||
rs_sysctrl_fault_status_t fault;
|
||||
rs_watchdog_status_t watchdog = {0};
|
||||
rs_tiny_rcu_snapshot_t reset_snapshot;
|
||||
uint64_t before;
|
||||
uint64_t after;
|
||||
uint8_t p6_result;
|
||||
const rs_watchdog_config_t watchdog_config = {
|
||||
.prescale_divider = 1U,
|
||||
.timeout_ticks = UINT32_C(20000),
|
||||
@@ -251,12 +271,21 @@ int main(void) {
|
||||
rs_mcu_finish(false, 1U);
|
||||
}
|
||||
printf("Hello retroSoC! Tiny MCU\n");
|
||||
if (rs_watchdog_get_status(&watchdog, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
if (rs_watchdog_get_status(&watchdog, RS_TIMEOUT_DEFAULT) != RS_OK ||
|
||||
rs_tiny_rcu_get_snapshot(&reset_snapshot) != RS_OK) {
|
||||
rs_mcu_finish(false, 2U);
|
||||
}
|
||||
if (watchdog.reset_count != 0U) {
|
||||
rs_mcu_finish(true, 0U);
|
||||
if ((reset_snapshot.reset_cause & UINT32_C(4)) != 0U) {
|
||||
/* P7 resets WDG functional state. The AON RCU owns the retained cause;
|
||||
* the SRAM cookie proves all pre-reset acceptance work completed. */
|
||||
const bool reset_valid =
|
||||
rs_mcu_watchdog_cookie == UINT32_C(0x57375037) && watchdog.reset_count == 0U &&
|
||||
reset_snapshot.current_profile == 0U && reset_snapshot.sys_hz == UINT32_C(24000000) &&
|
||||
reset_snapshot.gate_status == 0U;
|
||||
rs_mcu_watchdog_cookie = 0U;
|
||||
rs_mcu_finish(reset_valid, reset_valid ? 0U : 2U);
|
||||
}
|
||||
rs_mcu_watchdog_cookie = 0U;
|
||||
if ((rs_archinfo_read(&info) != RS_OK) || (rs_archinfo_validate_build(&info) != RS_OK) ||
|
||||
(info.soc_id != RS_SOC_ID) || (info.topology != UINT32_C(0x20200001)) ||
|
||||
(info.technology != RS_SOC_TECHNOLOGY_ID) ||
|
||||
@@ -267,11 +296,14 @@ int main(void) {
|
||||
}
|
||||
if ((rs_mcu_compressed_probe() != 42U) || ((__RV_CSR_READ(CSR_MISA) & UINT32_C(1)) != 0U) ||
|
||||
(rs_irq_register_exception(2U, rs_mcu_exception) != RS_OK) ||
|
||||
(rs_irq_register_exception(5U, rs_mcu_exception) != RS_OK)) {
|
||||
(rs_irq_register_exception(5U, rs_mcu_exception) != RS_OK) ||
|
||||
(rs_irq_register_exception(7U, rs_mcu_exception) != RS_OK)) {
|
||||
rs_mcu_finish(false, 4U);
|
||||
}
|
||||
rs_mcu_probes_active = true;
|
||||
rs_mcu_atomic_probe(rs_mcu_source);
|
||||
rs_mcu_unmapped_probe();
|
||||
rs_mcu_probes_active = false;
|
||||
if ((rs_mcu_exception_count != 2U) || rs_mcu_handler_failed ||
|
||||
(rs_sysctrl_get_fault_status(&fault) != RS_OK) || !fault.pending ||
|
||||
(fault.address != UINT32_C(0x38000000)) || (rs_sysctrl_clear_fault() != RS_OK)) {
|
||||
@@ -289,9 +321,14 @@ int main(void) {
|
||||
rs_mcu_finish(false, 8U);
|
||||
}
|
||||
if (!rs_mcu_io()) {
|
||||
rs_mcu_finish(false, 10U);
|
||||
rs_mcu_finish(false, rs_mcu_io_code);
|
||||
}
|
||||
p6_result = rs_tiny_p6_acceptance();
|
||||
if (p6_result != 0U) {
|
||||
rs_mcu_finish(false, p6_result);
|
||||
}
|
||||
printf("Tiny CPU/DMA/IRQ/RTC/I/O passed; exercising watchdog reset\n");
|
||||
rs_mcu_watchdog_cookie = UINT32_C(0x57375037);
|
||||
if ((rs_watchdog_configure(&watchdog_config) != RS_OK) ||
|
||||
(rs_watchdog_start(RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
rs_mcu_finish(false, 9U);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
APP_SRCS += $(ROOT_PATH)/app/apps/ci_smoke/tiny.c
|
||||
APP_CFLAGS += -Os
|
||||
APP_SRCS += $(ROOT_PATH)/app/apps/ci_smoke/mcu_acceptance.S
|
||||
APP_SRCS += $(ROOT_PATH)/app/apps/ci_smoke/tiny_r2_p6.c
|
||||
ifeq ($(TINY_P7_ACCEPTANCE),YES)
|
||||
APP_SRCS := $(ROOT_PATH)/app/apps/ci_smoke/tiny_r2_p7.c
|
||||
endif
|
||||
@@ -0,0 +1,801 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/arch/riscv/system_base.h>
|
||||
#include <retrosoc/core/irq.h>
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/generated/irq_metadata.h>
|
||||
#include <retrosoc/hal/clint.h>
|
||||
#include <retrosoc/hal/crc.h>
|
||||
#include <retrosoc/hal/crypto.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/i2s.h>
|
||||
#include <retrosoc/hal/rng.h>
|
||||
#include <retrosoc/hal/sdio.h>
|
||||
#include <retrosoc/hal/uart.h>
|
||||
#include <retrosoc/hal/ws2812.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
|
||||
#include "mcu_shared_acceptance.h"
|
||||
|
||||
static volatile uint32_t rs_p6_irq_count;
|
||||
static uint32_t rs_p6_irq_selected;
|
||||
static volatile bool rs_p6_irq_error;
|
||||
static _Alignas(64) uint32_t rs_p6_source[256];
|
||||
static _Alignas(64) uint32_t rs_p6_destination[258];
|
||||
static _Alignas(64) uint32_t rs_p6_audio_tx[768];
|
||||
static _Alignas(64) uint32_t rs_p6_audio_rx[562];
|
||||
static _Alignas(64) rs_dma_tcd_t rs_p6_descriptors[4];
|
||||
static rs_dma_session_t rs_p6_audio_tx_owner;
|
||||
static rs_dma_session_t rs_p6_audio_rx_owner;
|
||||
static rs_dma_session_t rs_p6_background_owner;
|
||||
static uint32_t rs_p6_pixels[65];
|
||||
|
||||
static void rs_p6_irq_handler(uintptr_t cause, uintptr_t stack) {
|
||||
(void)cause;
|
||||
(void)stack;
|
||||
++rs_p6_irq_count;
|
||||
if (rs_irq_disable_external(rs_p6_irq_selected) != RS_OK) {
|
||||
rs_p6_irq_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool rs_p6_irq_arm(uint32_t irq) {
|
||||
rs_p6_irq_selected = irq;
|
||||
rs_p6_irq_count = 0U;
|
||||
rs_p6_irq_error = false;
|
||||
if ((rs_irq_register_external(irq, rs_p6_irq_handler) != RS_OK) ||
|
||||
(rs_irq_enable_external(irq, rs_p6_irq_handler) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
__RV_CSR_SET(CSR_MSTATUS, UINT32_C(8));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p6_irq_received(void) {
|
||||
uint32_t timeout = UINT32_C(100000);
|
||||
while ((rs_p6_irq_count == 0U) && (timeout != 0U)) {
|
||||
--timeout;
|
||||
}
|
||||
return (rs_p6_irq_count == 1U) && !rs_p6_irq_error;
|
||||
}
|
||||
|
||||
static bool rs_p6_route(uint32_t pin, bool open_drain) {
|
||||
const rs_gpio_config_t config = {
|
||||
.mode = RS_GPIO_MODE_ALT0,
|
||||
.pull = RS_GPIO_PULL_NONE,
|
||||
.trigger = RS_GPIO_TRIGGER_NONE,
|
||||
.open_drain = open_drain,
|
||||
.filter_enable = false,
|
||||
};
|
||||
return rs_gpio_configure(pin, &config) == RS_OK;
|
||||
}
|
||||
|
||||
static bool rs_p6_uart(void) {
|
||||
const uint8_t transmit[4] = {0xA5U, 0x5AU, 0x96U, 0x69U};
|
||||
rs_uart_rx_data_t receive[4];
|
||||
const rs_uart_config_t unsupported = {
|
||||
.source_clock_hz = RS_PCLK_CLOCK_HZ,
|
||||
.baud_rate = UART_BPS,
|
||||
.data_bits = 8U,
|
||||
.stop_bits = 1U,
|
||||
.parity = RS_UART_PARITY_NONE,
|
||||
.rx_watermark = 1U,
|
||||
.rx_timeout_bits = 16U,
|
||||
.tx_enable = true,
|
||||
.rx_enable = true,
|
||||
.auto_cts_enable = true,
|
||||
};
|
||||
if ((rs_uart_configure(&unsupported, RS_TIMEOUT_DEFAULT) != RS_ENOTSUP) ||
|
||||
(rs_uart_write(transmit, sizeof(transmit), RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_uart_read(receive, 4U, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t index = 0U; index < 4U; ++index) {
|
||||
if (receive[index].data != transmit[index] || receive[index].errors != 0U) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
printf("\nR2_P6_UART pads=1 echo_bytes=4 flow_rejected=1\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p6_rng(void) {
|
||||
const rs_rng_config_t config = {.fifo_watermark = 1U};
|
||||
rs_rng_snapshot_t snapshot;
|
||||
uint32_t word = 0U;
|
||||
if ((rs_rng_init(&config) != RS_OK) ||
|
||||
(rs_rng_read_entropy(&word, RS_TIMEOUT_DEFAULT) != RS_ENOTSUP) ||
|
||||
(rs_rng_read_diagnostic(&word, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_rng_get_status(&snapshot) != RS_OK) || snapshot.source_qualified ||
|
||||
!rs_p6_irq_arm(RS_SOC_EXT_IRQ_RNG) ||
|
||||
(rs_rng_interrupt_enable(RS_RNG_INTERRUPT_SOURCE_FAULT) != RS_OK) ||
|
||||
(rs_rng_interrupt_test(RS_RNG_INTERRUPT_SOURCE_FAULT) != RS_OK) || !rs_p6_irq_received() ||
|
||||
(rs_rng_interrupt_enable(0U) != RS_OK) ||
|
||||
(rs_rng_interrupt_clear(RS_RNG_INTERRUPT_ALL) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_RNG unqualified=1 diagnostic=1 irq=1\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p6_dma_capabilities(void) {
|
||||
const uint32_t capability = RS_DMA_REG(RS_DMA_REG_CAPABILITY);
|
||||
rs_dma_config_t config = {
|
||||
.kind = RS_DMA_KIND_MM_TO_MM,
|
||||
.request = RS_DMA_REQUEST_SOFTWARE,
|
||||
.source = (uintptr_t)rs_p6_source,
|
||||
.destination = (uintptr_t)rs_p6_destination,
|
||||
.byte_count = 4U,
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.source_increment = true,
|
||||
.destination_increment = true,
|
||||
.burst_beats = 1U,
|
||||
};
|
||||
rs_dma_status_t status;
|
||||
const uint32_t unsupported[] = {9U, 10U, 11U, 14U, 15U};
|
||||
if (((capability >> 8U) & UINT32_C(0xFF)) != 8U) {
|
||||
return false;
|
||||
}
|
||||
for (size_t index = 0U; index < sizeof(unsupported) / sizeof(unsupported[0]); ++index) {
|
||||
rs_p6_destination[0] = UINT32_C(0x12345678);
|
||||
if (rs_dma_configure(RS_DMA_CHANNEL_DVP, &config) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
/* Exercise hardware rejection independently of the SDK's earlier gate. */
|
||||
RS_DMA_CH_REG(RS_DMA_CHANNEL_DVP, RS_DMA_CH_REG_REQUEST_SEL) = unsupported[index];
|
||||
if ((rs_dma_start(RS_DMA_CHANNEL_DVP) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_DVP, RS_TIMEOUT_DEFAULT) != RS_EIO) ||
|
||||
(rs_dma_get_status(RS_DMA_CHANNEL_DVP, &status) != RS_OK) || !status.error ||
|
||||
status.busy || (status.bytes_done != 0U) ||
|
||||
(rs_p6_destination[0] != UINT32_C(0x12345678))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
printf("R2_P6_DMA channels=8 rejected_requests=5\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t rs_p6_crc_reference(const uint8_t *data, size_t bytes) {
|
||||
uint32_t value = UINT32_MAX;
|
||||
for (size_t index = 0U; index < bytes; ++index) {
|
||||
value ^= (uint32_t)data[index];
|
||||
for (uint32_t bit = 0U; bit < 8U; ++bit) {
|
||||
value = (value >> 1U) ^ (((value & 1U) != 0U) ? UINT32_C(0xEDB88320) : 0U);
|
||||
}
|
||||
}
|
||||
return ~value;
|
||||
}
|
||||
|
||||
static bool rs_p6_crc(void) {
|
||||
rs_crc_config_t crc;
|
||||
static rs_dma_session_t lease;
|
||||
uint32_t result;
|
||||
rs_dma_config_t transfer = {
|
||||
.kind = RS_DMA_KIND_MM_TO_MM,
|
||||
.request = RS_DMA_REQUEST_SOFTWARE,
|
||||
.source = (uintptr_t)rs_p6_source,
|
||||
.destination = RS_SOC_APB4_CRC_BASE + CRC_DATA_OFFSET,
|
||||
.byte_count = UINT32_C(64),
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.source_increment = true,
|
||||
.burst_beats = 1U,
|
||||
};
|
||||
for (uint32_t index = 0U; index < 256U; ++index) {
|
||||
rs_p6_source[index] = UINT32_C(0x12345678) ^ (index * UINT32_C(0x01020408));
|
||||
}
|
||||
if ((rs_crc_get_profile(RS_CRC_PROFILE_CRC32_ISO_HDLC, &crc) != RS_OK) ||
|
||||
(rs_dma_session_acquire(&lease, RS_DMA_CHANNEL_BULK) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
for (size_t tail = 0U; tail < 4U; ++tail) {
|
||||
if ((rs_crc_init(&crc) != RS_OK) || (rs_crc_start() != RS_OK) ||
|
||||
(rs_dma_session_configure(&lease, &transfer) != RS_OK) ||
|
||||
(rs_dma_session_start(&lease) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_BULK, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_crc_update((const uint8_t *)rs_p6_source + 64U, tail) != RS_OK) ||
|
||||
(rs_crc_finish(&result) != RS_OK) ||
|
||||
(result != rs_p6_crc_reference((const uint8_t *)rs_p6_source, 64U + tail))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_dma_session_release(&lease) != RS_OK) ||
|
||||
(rs_crc_compute(&crc, rs_p6_source, 0U, &result) != RS_OK) || (result != 0U)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_CRC dma=1 tails=4 empty=1\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p6_crypto(void) {
|
||||
static uint32_t modulus[RS_CRYPTO_RSA_WORDS];
|
||||
static uint32_t base[RS_CRYPTO_RSA_WORDS];
|
||||
static uint32_t exponent[RS_CRYPTO_RSA_WORDS];
|
||||
static uint32_t rsa_result[RS_CRYPTO_RSA_WORDS];
|
||||
static const uint8_t key[16] = {
|
||||
0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U,
|
||||
0x08U, 0x09U, 0x0AU, 0x0BU, 0x0CU, 0x0DU, 0x0EU, 0x0FU,
|
||||
};
|
||||
static const uint32_t input[4] = {
|
||||
UINT32_C(0x33221100),
|
||||
UINT32_C(0x77665544),
|
||||
UINT32_C(0xBBAA9988),
|
||||
UINT32_C(0xFFEEDDCC),
|
||||
};
|
||||
static const uint32_t expected[4] = {
|
||||
UINT32_C(0xD8E0C469),
|
||||
UINT32_C(0x30047B6A),
|
||||
UINT32_C(0x80B7CDD8),
|
||||
UINT32_C(0x5AC5B470),
|
||||
};
|
||||
if ((rs_crypto_zeroize_wait(1U) != RS_ETIMEOUT) ||
|
||||
(rs_crypto_zeroize_wait(RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_crypto_init(2050U) != RS_ETIMEOUT) ||
|
||||
(rs_crypto_selftest(RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_crypto_aes_set_key(key, sizeof(key), RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t index = 0U; index < 16U; ++index) {
|
||||
rs_p6_source[index] = input[index % 4U];
|
||||
}
|
||||
rs_p6_destination[0] = UINT32_C(0x5A5AA5A5);
|
||||
rs_p6_destination[17] = UINT32_C(0xA5A55A5A);
|
||||
if (rs_crypto_aes_crypt_dma(RS_CRYPTO_AES_ECB, false, NULL, rs_p6_source, &rs_p6_destination[1],
|
||||
64U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t index = 0U; index < 16U; ++index) {
|
||||
if (rs_p6_destination[index + 1U] != expected[index % 4U]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* A small public-operation integration vector exercises the full 2048-bit
|
||||
* storage/control path. Full private vectors remain in the shared suite. */
|
||||
for (uint32_t index = 0U; index < RS_CRYPTO_RSA_WORDS; ++index) {
|
||||
modulus[index] = UINT32_MAX;
|
||||
}
|
||||
base[0] = 2U;
|
||||
exponent[0] = 3U;
|
||||
if ((rs_crypto_rsa_prepare(modulus, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_crypto_rsa_modexp(base, exponent, 2U, false, rsa_result, RS_TIMEOUT_DEFAULT) !=
|
||||
RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t index = 0U; index < RS_CRYPTO_RSA_WORDS; ++index) {
|
||||
if (rsa_result[index] != ((index == 0U) ? 8U : 0U)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_p6_destination[0] != UINT32_C(0x5A5AA5A5)) ||
|
||||
(rs_p6_destination[17] != UINT32_C(0xA5A55A5A)) || !rs_p6_irq_arm(RS_SOC_EXT_IRQ_CRYPTO)) {
|
||||
return false;
|
||||
}
|
||||
RS_CRYPTO_REG(RS_CRYPTO_REG_IRQ_STATE) = RS_CRYPTO_IRQ_ALL;
|
||||
RS_CRYPTO_REG(RS_CRYPTO_REG_IRQ_ENABLE) = RS_CRYPTO_IRQ_ZEROIZED;
|
||||
if ((rs_crypto_zeroize_wait(0U) != RS_ETIMEOUT) ||
|
||||
(rs_crypto_zeroize_wait(RS_TIMEOUT_DEFAULT) != RS_OK) || !rs_p6_irq_received()) {
|
||||
return false;
|
||||
}
|
||||
RS_CRYPTO_REG(RS_CRYPTO_REG_IRQ_ENABLE) = 0U;
|
||||
RS_CRYPTO_REG(RS_CRYPTO_REG_IRQ_STATE) = RS_CRYPTO_IRQ_ALL;
|
||||
printf("R2_P6_CRYPTO init=1 aes_sha=1 dma45=1 rsa_public=1 zeroize=1\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p6_stop_session(rs_dma_session_t *owner) {
|
||||
rs_dma_status_t status;
|
||||
uint32_t timeout = UINT32_C(100000);
|
||||
if ((rs_dma_get_status(owner->channel, &status) != RS_OK) ||
|
||||
(status.busy && (rs_dma_session_abort(owner) != RS_OK))) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if ((rs_dma_get_status(owner->channel, &status) != RS_OK) || (timeout == 0U)) {
|
||||
return false;
|
||||
}
|
||||
--timeout;
|
||||
} while (status.busy);
|
||||
return rs_dma_session_release(owner) == RS_OK;
|
||||
}
|
||||
|
||||
static uint32_t rs_p6_audio_sample(bool wide, uint32_t index) {
|
||||
const uint32_t word = rs_p6_audio_rx[1U + (wide ? index : index / 2U)];
|
||||
return wide ? word : ((word >> ((index % 2U) * 16U)) & UINT32_C(0xFFFF));
|
||||
}
|
||||
|
||||
static bool rs_p6_audio_words(bool wide, uint32_t received_words) {
|
||||
const uint32_t samples = wide ? received_words : received_words * 2U;
|
||||
const uint32_t first = wide ? UINT32_C(0x120020) : UINT32_C(0x2020);
|
||||
uint32_t offset = 0U;
|
||||
/* Ignore only the bounded PHY startup preamble, never a missing payload.
|
||||
* Exactly 256 stereo frames must then match consecutive independent samples. */
|
||||
while ((offset < 40U) && (rs_p6_audio_sample(wide, offset) != first)) {
|
||||
++offset;
|
||||
}
|
||||
if ((offset >= 40U) || ((offset + 512U) > samples)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t sample = 0U; sample < 512U; ++sample) {
|
||||
if (rs_p6_audio_sample(wide, offset + sample) != (first + sample)) {
|
||||
printf("R2_P6_AUDIO mismatch wide=%u sample=%lu got=%lx expected=%lx\n", wide ? 1U : 0U,
|
||||
(unsigned long)sample, (unsigned long)rs_p6_audio_sample(wide, offset + sample),
|
||||
(unsigned long)(first + sample));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (rs_p6_audio_rx[0] == UINT32_C(0x5A5AA5A5)) &&
|
||||
(rs_p6_audio_rx[received_words + 1U] == UINT32_C(0xA5A55A5A));
|
||||
}
|
||||
|
||||
static bool rs_p6_audio_ws(bool wide) {
|
||||
printf("R2_P6_STAGE audio_bits=%u cycles=%lu\n", wide ? 24U : 16U,
|
||||
(unsigned long)__RV_CSR_READ(CSR_MCYCLE));
|
||||
const uint32_t rx_words = wide ? 548U : 280U;
|
||||
const rs_i2s_config_t audio = {
|
||||
.stream_tx = true,
|
||||
.stream_rx = true,
|
||||
.preset = wide ? RS_I2S_PRESET_24B_48K : RS_I2S_PRESET_16B_48K,
|
||||
.upbound = 96U,
|
||||
.lowbound = 32U,
|
||||
};
|
||||
const rs_ws2812_config_t ws = {
|
||||
.source_clock_hz = RS_PCLK_CLOCK_HZ,
|
||||
.bit_period_ns = 1250U,
|
||||
.t0h_ns = 350U,
|
||||
.t1h_ns = 700U,
|
||||
.reset_ns = 300000U,
|
||||
.fifo_watermark = 8U,
|
||||
};
|
||||
rs_dma_config_t tx = {
|
||||
.kind = RS_DMA_KIND_MM_TO_STREAM,
|
||||
.request = RS_DMA_REQUEST_I2S_TX,
|
||||
.source = (uintptr_t)rs_p6_audio_tx,
|
||||
.byte_count = sizeof(rs_p6_audio_tx),
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.source_increment = true,
|
||||
.priority = 3U,
|
||||
.burst_beats = 16U,
|
||||
};
|
||||
rs_dma_config_t rx = {
|
||||
.kind = RS_DMA_KIND_STREAM_TO_MM,
|
||||
.request = RS_DMA_REQUEST_I2S_RX,
|
||||
.destination = (uintptr_t)&rs_p6_audio_rx[1],
|
||||
.byte_count = rx_words * 4U,
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.destination_increment = true,
|
||||
.priority = 3U,
|
||||
.burst_beats = 16U,
|
||||
};
|
||||
rs_dma_config_t background = {
|
||||
.kind = RS_DMA_KIND_MM_TO_MM,
|
||||
.request = RS_DMA_REQUEST_SOFTWARE,
|
||||
.source = (uintptr_t)rs_p6_source,
|
||||
.destination = (uintptr_t)&rs_p6_destination[1],
|
||||
.byte_count = 256U,
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.source_increment = true,
|
||||
.destination_increment = true,
|
||||
.burst_beats = 16U,
|
||||
};
|
||||
rs_i2s_status_t audio_status;
|
||||
rs_dma_status_t rx_status, bg_status;
|
||||
rs_ws2812_dma_status_t ws_status;
|
||||
uint64_t now, deadline, start;
|
||||
uint32_t cycles, instructions;
|
||||
uint32_t frame = 0U, background_jobs = 0U;
|
||||
for (uint32_t pin = 12U; pin <= 17U; ++pin) {
|
||||
if (!rs_p6_route(pin, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!rs_p6_route(26U, false) || (rs_i2s_disable() != RS_OK) ||
|
||||
(rs_i2s_flush(true, true, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_i2s_configure(&audio) != RS_OK) || (rs_ws2812_init(&ws) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_STAGE audio_host_ready=1 cycles=%lu\n", (unsigned long)__RV_CSR_READ(CSR_MCYCLE));
|
||||
for (uint32_t index = 0U; index < 768U; ++index) {
|
||||
rs_p6_audio_tx[index] =
|
||||
wide ? UINT32_C(0x120000) + index
|
||||
: ((UINT32_C(0x2001) + 2U * index) << 16U) | (UINT32_C(0x2000) + 2U * index);
|
||||
}
|
||||
for (uint32_t index = 0U; index < 65U; ++index) {
|
||||
rs_p6_pixels[index] = index * UINT32_C(0x010203);
|
||||
}
|
||||
for (uint32_t index = 0U; index < 256U; ++index) {
|
||||
rs_p6_source[index] = UINT32_C(0x5A123456) ^ index;
|
||||
rs_p6_destination[index + 1U] = 0U;
|
||||
}
|
||||
rs_p6_destination[0] = UINT32_C(0x5A5AA5A5);
|
||||
rs_p6_destination[257] = UINT32_C(0xA5A55A5A);
|
||||
rs_p6_audio_rx[0] = UINT32_C(0x5A5AA5A5);
|
||||
rs_p6_audio_rx[rx_words + 1U] = UINT32_C(0xA5A55A5A);
|
||||
for (uint32_t index = 0U; index < 4U; ++index) {
|
||||
rs_p6_descriptors[index] = (rs_dma_tcd_t){
|
||||
.source = (uint32_t)(uintptr_t)&rs_p6_source[index * 64U],
|
||||
.destination = (uint32_t)(uintptr_t)&rs_p6_destination[1U + index * 64U],
|
||||
.byte_count = 256U,
|
||||
.next_ptr = index == 3U ? 0U : (uint32_t)(uintptr_t)&rs_p6_descriptors[index + 1U],
|
||||
.control = RS_DMA_TCD_VALID | RS_DMA_TCD_SRC_INC | RS_DMA_TCD_DST_INC |
|
||||
(UINT32_C(16) << RS_DMA_TCD_BURST_SHIFT),
|
||||
};
|
||||
}
|
||||
if (!rs_p6_irq_arm(RS_SOC_EXT_IRQ_I2S) ||
|
||||
(rs_i2s_interrupt_enable(RS_I2S_INTERRUPT_TX_LOW) != RS_OK) ||
|
||||
(rs_i2s_interrupt_test(RS_I2S_INTERRUPT_TX_LOW) != RS_OK) || !rs_p6_irq_received() ||
|
||||
(rs_i2s_interrupt_enable(0U) != RS_OK) ||
|
||||
(rs_i2s_interrupt_clear(RS_I2S_INTERRUPT_ALL) != RS_OK) ||
|
||||
(rs_dma_session_acquire(&rs_p6_audio_tx_owner, RS_DMA_CHANNEL_I2S_TX) != RS_OK) ||
|
||||
(rs_dma_session_acquire(&rs_p6_audio_rx_owner, RS_DMA_CHANNEL_I2S_RX) != RS_OK) ||
|
||||
(rs_dma_session_acquire(&rs_p6_background_owner, RS_DMA_CHANNEL_DVP) != RS_OK) ||
|
||||
(rs_dma_session_configure(&rs_p6_audio_tx_owner, &tx) != RS_OK) ||
|
||||
(rs_dma_session_configure(&rs_p6_audio_rx_owner, &rx) != RS_OK) ||
|
||||
(rs_dma_session_start(&rs_p6_audio_tx_owner) != RS_OK) ||
|
||||
(rs_dma_session_start(&rs_p6_audio_rx_owner) != RS_OK) ||
|
||||
(rs_clint_get_time(&start) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
deadline = start + UINT64_C(50000);
|
||||
printf("R2_P6_STAGE audio_dma_started=1 cycles=%lu\n",
|
||||
(unsigned long)__RV_CSR_READ(CSR_MCYCLE));
|
||||
do {
|
||||
if ((rs_i2s_get_status(&audio_status) != RS_OK) || (rs_clint_get_time(&now) != RS_OK) ||
|
||||
(now >= deadline)) {
|
||||
return false;
|
||||
}
|
||||
} while (audio_status.tx_level < 96U);
|
||||
printf("R2_P6_STAGE audio_prefilled=1 cycles=%lu\n", (unsigned long)__RV_CSR_READ(CSR_MCYCLE));
|
||||
cycles = (uint32_t)__RV_CSR_READ(CSR_MCYCLE);
|
||||
instructions = (uint32_t)__RV_CSR_READ(CSR_MINSTRET);
|
||||
if (!rs_p6_irq_arm(RS_SOC_EXT_IRQ_WS2812) ||
|
||||
(rs_ws2812_irq_enable(RS_WS2812_INTR_FIFO_LOW | RS_WS2812_INTR_DONE) != RS_OK) ||
|
||||
(rs_i2s_enable(true, true) != RS_OK) ||
|
||||
(rs_ws2812_dma_begin(rs_p6_pixels, 33U, now, deadline) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if ((rs_clint_get_time(&now) != RS_OK) || (now >= deadline) ||
|
||||
(rs_ws2812_dma_service(now) != RS_OK) || (rs_ws2812_dma_status(&ws_status) != RS_OK) ||
|
||||
(rs_dma_get_status(RS_DMA_CHANNEL_I2S_RX, &rx_status) != RS_OK) ||
|
||||
(rs_dma_get_status(RS_DMA_CHANNEL_DVP, &bg_status) != RS_OK) || rx_status.error ||
|
||||
bg_status.error) {
|
||||
return false;
|
||||
}
|
||||
if (!bg_status.busy && (background_jobs < 64U)) {
|
||||
if (rs_dma_session_configure(&rs_p6_background_owner, &background) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
/* This application exclusively leases channel 2; the ordinary TCD
|
||||
* helper is blocking, so publish the same finite hardware chain. */
|
||||
RS_DMA_CH_REG(RS_DMA_CHANNEL_DVP, RS_DMA_CH_REG_TCD_HEAD) =
|
||||
wide ? (uint32_t)(uintptr_t)rs_p6_descriptors : 0U;
|
||||
RS_DMA_CH_REG(RS_DMA_CHANNEL_DVP, RS_DMA_CH_REG_TCD_COUNT) = wide ? 4U : 0U;
|
||||
if (rs_dma_session_start(&rs_p6_background_owner) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
++background_jobs;
|
||||
}
|
||||
if (!ws_status.active && (frame == 0U)) {
|
||||
if ((ws_status.result != RS_OK) ||
|
||||
(rs_ws2812_dma_begin(rs_p6_pixels, 65U, now, deadline) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
frame = 1U;
|
||||
ws_status.active = true;
|
||||
}
|
||||
} while (rx_status.busy || ws_status.active);
|
||||
cycles = (uint32_t)__RV_CSR_READ(CSR_MCYCLE) - cycles;
|
||||
instructions = (uint32_t)__RV_CSR_READ(CSR_MINSTRET) - instructions;
|
||||
if ((rx_status.bytes_done != rx_words * 4U) || !rx_status.done || (ws_status.result != RS_OK) ||
|
||||
(rs_p6_irq_count != 1U) || (rs_i2s_get_status(&audio_status) != RS_OK) ||
|
||||
((audio_status.interrupt_state &
|
||||
(RS_I2S_INTERRUPT_TX_UNDERRUN | RS_I2S_INTERRUPT_RX_OVERRUN)) != 0U) ||
|
||||
!rs_p6_stop_session(&rs_p6_audio_tx_owner) || !rs_p6_stop_session(&rs_p6_audio_rx_owner) ||
|
||||
(rs_i2s_disable() != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_DVP, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_dma_session_release(&rs_p6_background_owner) != RS_OK) ||
|
||||
(rs_i2s_flush(true, true, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_ws2812_irq_enable(0U) != RS_OK) || !rs_p6_audio_words(wide, rx_words)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t index = 0U; index < (wide ? 256U : 64U); ++index) {
|
||||
if (rs_p6_destination[index + 1U] != rs_p6_source[index]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_p6_destination[0] != UINT32_C(0x5A5AA5A5)) ||
|
||||
(rs_p6_destination[257] != UINT32_C(0xA5A55A5A))) {
|
||||
return false;
|
||||
}
|
||||
if (!wide) {
|
||||
for (uint32_t index = 65U; index <= 256U; ++index) {
|
||||
if (rs_p6_destination[index] != 0U) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("R2_P6_AUDIO bits=%u frames=256 ws_frames=2 background_jobs=%lu tcd=%u elapsed_us=%lu "
|
||||
"cycles=%lu instructions=%lu\n",
|
||||
wide ? 24U : 16U, (unsigned long)background_jobs, wide ? 1U : 0U,
|
||||
(unsigned long)(now - start), (unsigned long)cycles, (unsigned long)instructions);
|
||||
return background_jobs != 0U;
|
||||
}
|
||||
|
||||
static bool rs_p6_audio_ws_recovery(void) {
|
||||
const rs_ws2812_config_t config = {
|
||||
.source_clock_hz = RS_PCLK_CLOCK_HZ,
|
||||
.bit_period_ns = 1250U,
|
||||
.t0h_ns = 350U,
|
||||
.t1h_ns = 700U,
|
||||
.reset_ns = 300000U,
|
||||
.fifo_watermark = 8U,
|
||||
};
|
||||
uint64_t now, began;
|
||||
rs_i2s_status_t audio;
|
||||
rs_ws2812_status_t ws;
|
||||
for (uint32_t phase = 0U; phase < 2U; ++phase) {
|
||||
if ((rs_gpio_write(27U, true) != RS_OK) || (rs_clint_get_time(&began) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if (rs_clint_get_time(&now) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
} while ((now - began) < 10U);
|
||||
if ((rs_i2s_flush(true, true, 16U) != RS_ETIMEOUT) ||
|
||||
(rs_i2s_get_status(&audio) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
/* A timed-out command remains owned by the controller. Do not issue
|
||||
* another COMMAND while BUSY: that write is correctly rejected. */
|
||||
do {
|
||||
if ((rs_i2s_get_status(&audio) != RS_OK) || (rs_clint_get_time(&now) != RS_OK) ||
|
||||
((now - began) > 1000U)) {
|
||||
return false;
|
||||
}
|
||||
} while ((audio.status & (RS_I2S_STATUS_TX_FLUSH_BUSY | RS_I2S_STATUS_RX_FLUSH_BUSY)) !=
|
||||
0U);
|
||||
if (rs_gpio_write(27U, false) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_ws2812_init(&config) != RS_OK) || (rs_ws2812_push(0U, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_ws2812_start(2U) != RS_OK) || (rs_ws2812_wait(RS_TIMEOUT_DEFAULT) != RS_EIO) ||
|
||||
(rs_ws2812_get_status(&ws) != RS_OK) ||
|
||||
((ws.error_status & RS_WS2812_ERROR_UNDERFLOW) == 0U) ||
|
||||
(rs_clint_get_time(&began) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if ((rs_ws2812_get_status(&ws) != RS_OK) || (rs_clint_get_time(&now) != RS_OK) ||
|
||||
((now - began) > 1000U)) {
|
||||
return false;
|
||||
}
|
||||
} while (ws.busy);
|
||||
if ((rs_ws2812_init(&config) != RS_OK) || (rs_ws2812_push(0U, RS_TIMEOUT_DEFAULT) != RS_OK) ||
|
||||
(rs_ws2812_start(65U) != RS_OK) || (rs_ws2812_abort(RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_RECOVERY audio_stops=2 ws_underflow=1 ws_abort=1\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p6_sdio_step(rs_status_t result, uint32_t step) {
|
||||
rs_sdio_status_t status;
|
||||
if (result == RS_OK) {
|
||||
return true;
|
||||
}
|
||||
if (rs_sdio_status_get(RS_SDIO_INSTANCE_0, &status) == RS_OK) {
|
||||
printf("R2_P6_SDIO_ERROR step=%lu result=%ld command=%lx data=%lx dma=%lx errors=%lx\n",
|
||||
(unsigned long)step, (long)result, (unsigned long)status.command_status,
|
||||
(unsigned long)status.data_status, (unsigned long)status.dma_status,
|
||||
(unsigned long)status.error_status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rs_p6_sdio(void) {
|
||||
static _Alignas(16) rs_sdio_descriptor_t descriptor;
|
||||
rs_sd_memory_info_t card;
|
||||
rs_sdio_clock_t clock;
|
||||
rs_sdio_response_t response;
|
||||
rs_dma_config_t background = {
|
||||
.kind = RS_DMA_KIND_MM_TO_MM,
|
||||
.request = RS_DMA_REQUEST_SOFTWARE,
|
||||
.source = (uintptr_t)rs_p6_audio_tx,
|
||||
.destination = (uintptr_t)&rs_p6_audio_rx[1],
|
||||
.byte_count = 1024U,
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.source_increment = true,
|
||||
.destination_increment = true,
|
||||
.burst_beats = 16U,
|
||||
};
|
||||
rs_sdio_command_t command = {
|
||||
.index = 17U,
|
||||
.argument = 1U,
|
||||
.response = RS_SDIO_RESPONSE_R1,
|
||||
.crc_check = true,
|
||||
.index_check = true,
|
||||
};
|
||||
const rs_sdio_data_config_t pio = {
|
||||
.block_size = 512U,
|
||||
.block_count = 1U,
|
||||
.direction = RS_SDIO_DATA_FROM_CARD,
|
||||
.dma = false,
|
||||
.block_mode = true,
|
||||
};
|
||||
const rs_sdio_data_config_t dma_write = {
|
||||
.block_size = 512U,
|
||||
.block_count = 2U,
|
||||
.direction = RS_SDIO_DATA_TO_CARD,
|
||||
.dma = true,
|
||||
.block_mode = true,
|
||||
};
|
||||
uint32_t id, version, capability;
|
||||
rs_status_t initialized;
|
||||
printf("R2_P6_STAGE sdio_begin=1\n");
|
||||
for (uint32_t pin = 0U; pin < 6U; ++pin) {
|
||||
if (!rs_p6_route(pin, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_sdio_probe(RS_SDIO_INSTANCE_1, &id, &version, &capability) != RS_ENOTSUP) ||
|
||||
(rs_sdio_controller_selftest(RS_SDIO_INSTANCE_0) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
initialized =
|
||||
rs_sd_memory_initialize(RS_SDIO_INSTANCE_0, RS_CPU_CLOCK_HZ, &card, RS_TIMEOUT_DEFAULT);
|
||||
printf("R2_P6_STAGE sdio_init=%ld clock=%lu width=%u rca=%u\n", (long)initialized,
|
||||
(unsigned long)card.actual_clock_hz, (unsigned)card.bus_width, (unsigned)card.rca);
|
||||
if ((initialized != RS_OK) || (card.actual_clock_hz != UINT32_C(12000000)) ||
|
||||
!card.high_capacity || (card.rca != 1U) || (card.bus_width != RS_SDIO_BUS_WIDTH_4)) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t index = 0U; index < 256U; ++index) {
|
||||
rs_p6_source[index] = UINT32_C(0x13579BDF) ^ index;
|
||||
rs_p6_destination[index + 1U] = 0U;
|
||||
rs_p6_audio_tx[index] = UINT32_C(0x55AA0000) + index;
|
||||
rs_p6_audio_rx[index + 1U] = ~rs_p6_audio_tx[index];
|
||||
}
|
||||
rs_p6_destination[0] = UINT32_C(0x5A5AA5A5);
|
||||
rs_p6_destination[257] = UINT32_C(0xA5A55A5A);
|
||||
command.index = 25U;
|
||||
if (!rs_p6_sdio_step(rs_dma_session_acquire(&rs_p6_background_owner, RS_DMA_CHANNEL_DVP), 1U) ||
|
||||
!rs_p6_sdio_step(rs_dma_session_configure(&rs_p6_background_owner, &background), 2U) ||
|
||||
!rs_p6_sdio_step(
|
||||
rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT),
|
||||
3U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_descriptor_prepare(&descriptor, (uintptr_t)rs_p6_source, 1024U,
|
||||
(uintptr_t)0U, true, false),
|
||||
4U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_dma_setup(RS_SDIO_INSTANCE_0, &descriptor, 1U, 1024U), 5U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_data_configure(RS_SDIO_INSTANCE_0, &dma_write), 6U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_data_start(RS_SDIO_INSTANCE_0), 7U) ||
|
||||
!rs_p6_sdio_step(rs_dma_session_start(&rs_p6_background_owner), 8U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_data_wait(RS_SDIO_INSTANCE_0, RS_TIMEOUT_DEFAULT), 9U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_dma_wait(RS_SDIO_INSTANCE_0, RS_TIMEOUT_DEFAULT), 10U)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_STAGE sdio_write=1\n");
|
||||
command.index = 12U;
|
||||
command.argument = 0U;
|
||||
command.response = RS_SDIO_RESPONSE_R1B;
|
||||
if (!rs_p6_sdio_step(
|
||||
rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT),
|
||||
11U) ||
|
||||
!rs_p6_sdio_step(rs_sd_memory_read_blocks(RS_SDIO_INSTANCE_0, &card, 1U, 2U,
|
||||
&rs_p6_destination[1], RS_TIMEOUT_DEFAULT),
|
||||
12U) ||
|
||||
!rs_p6_sdio_step(rs_dma_wait(RS_DMA_CHANNEL_DVP, RS_TIMEOUT_DEFAULT), 13U) ||
|
||||
!rs_p6_sdio_step(rs_dma_session_release(&rs_p6_background_owner), 14U)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_STAGE sdio_read=1\n");
|
||||
for (uint32_t index = 0U; index < 256U; ++index) {
|
||||
if ((rs_p6_destination[index + 1U] != rs_p6_source[index]) ||
|
||||
(rs_p6_audio_rx[index + 1U] != rs_p6_audio_tx[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_p6_destination[0] != UINT32_C(0x5A5AA5A5)) ||
|
||||
(rs_p6_destination[257] != UINT32_C(0xA5A55A5A)) ||
|
||||
(rs_sdio_clock_set(RS_SDIO_INSTANCE_0, RS_CPU_CLOCK_HZ, 400000U, &clock) != RS_OK) ||
|
||||
(clock.actual_hz != 400000U)) {
|
||||
return false;
|
||||
}
|
||||
/* Select one-bit card and host consistently before the PIO read. */
|
||||
command.index = 55U;
|
||||
command.argument = (uint32_t)card.rca << 16U;
|
||||
command.response = RS_SDIO_RESPONSE_R1;
|
||||
if (rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT) !=
|
||||
RS_OK) {
|
||||
return false;
|
||||
}
|
||||
command.index = 6U;
|
||||
command.argument = 0U;
|
||||
if ((rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT) !=
|
||||
RS_OK) ||
|
||||
(rs_sdio_bus_width_set(RS_SDIO_INSTANCE_0, RS_SDIO_BUS_WIDTH_1) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
command.index = 17U;
|
||||
command.argument = 1U;
|
||||
if (!rs_p6_sdio_step(
|
||||
rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT),
|
||||
15U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_data_configure(RS_SDIO_INSTANCE_0, &pio), 16U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_data_start(RS_SDIO_INSTANCE_0), 17U) ||
|
||||
!rs_p6_sdio_step(
|
||||
rs_sdio_pio_read(RS_SDIO_INSTANCE_0, &rs_p6_destination[1], 512U, RS_TIMEOUT_DEFAULT),
|
||||
18U) ||
|
||||
!rs_p6_sdio_step(rs_sdio_data_wait(RS_SDIO_INSTANCE_0, RS_TIMEOUT_DEFAULT), 19U)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_STAGE sdio_pio=1\n");
|
||||
for (uint32_t index = 0U; index < 128U; ++index) {
|
||||
if (rs_p6_destination[index + 1U] != rs_p6_source[index]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((rs_sdio_irq_clear(RS_SDIO_INSTANCE_0, RS_SDIO_IRQ_ALL) != RS_OK) ||
|
||||
!rs_p6_irq_arm(RS_SOC_EXT_IRQ_SDIO) ||
|
||||
(rs_sdio_irq_enable(RS_SDIO_INSTANCE_0, RS_SDIO_IRQ_ALL) != RS_OK) ||
|
||||
(rs_sdio_irq_test(RS_SDIO_INSTANCE_0, 1U) != RS_OK) || !rs_p6_irq_received() ||
|
||||
(rs_sdio_irq_enable(RS_SDIO_INSTANCE_0, 0U) != RS_OK) ||
|
||||
(rs_sdio_irq_clear(RS_SDIO_INSTANCE_0, RS_SDIO_IRQ_ALL) != RS_OK) ||
|
||||
(rs_sdio_timeouts_set(RS_SDIO_INSTANCE_0, 24000U, 24000U, 24000U) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
/* Verification card injects faults on these documented CMD13 arguments. */
|
||||
command.index = 13U;
|
||||
command.argument = UINT32_C(0xBADC0DE0);
|
||||
if (rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT) !=
|
||||
RS_EFORMAT) {
|
||||
return false;
|
||||
}
|
||||
command.argument = UINT32_C(0xBADC0DE1);
|
||||
if (rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT) !=
|
||||
RS_ETIMEOUT) {
|
||||
return false;
|
||||
}
|
||||
command.argument = (uint32_t)card.rca << 16U;
|
||||
if ((rs_sdio_error_clear(RS_SDIO_INSTANCE_0, RS_SDIO_ERROR_ALL) != RS_OK) ||
|
||||
(rs_sdio_command_execute(RS_SDIO_INSTANCE_0, &command, &response, RS_TIMEOUT_DEFAULT) !=
|
||||
RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
printf("R2_P6_SDIO dma_bytes=2048 pio_bytes=512 width1=1 width4=1 irq=1 errors=2\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t rs_tiny_p6_acceptance(void) {
|
||||
if (!rs_p6_uart()) {
|
||||
return 27U;
|
||||
}
|
||||
if (!rs_p6_dma_capabilities()) {
|
||||
return 19U;
|
||||
}
|
||||
if (!rs_p6_rng()) {
|
||||
return 20U;
|
||||
}
|
||||
if (!rs_p6_crc()) {
|
||||
return 21U;
|
||||
}
|
||||
if (!rs_p6_crypto()) {
|
||||
return 22U;
|
||||
}
|
||||
if (!rs_p6_audio_ws(false)) {
|
||||
return 23U;
|
||||
}
|
||||
if (!rs_p6_audio_ws(true)) {
|
||||
return 24U;
|
||||
}
|
||||
if (!rs_p6_audio_ws_recovery()) {
|
||||
return 26U;
|
||||
}
|
||||
if (!rs_p6_sdio()) {
|
||||
return 25U;
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/arch/riscv/system_base.h>
|
||||
#include <retrosoc/hal/clint.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/rcu.h>
|
||||
#include <retrosoc/hal/rcu_regs.h>
|
||||
#include <retrosoc/hal/sysctrl.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
#include <pwm_regs.h>
|
||||
|
||||
/* Short P7 firmware: execute in real main SRAM and use real SYSCTRL/APB
|
||||
* crossings. The full peripheral firmware remains a separate regression. */
|
||||
static volatile uint32_t rs_p7_words[128];
|
||||
static _Alignas(64) uint32_t rs_p7_source[1024];
|
||||
static _Alignas(64) uint32_t rs_p7_destination[1024];
|
||||
static volatile uint32_t rs_p7_retained __attribute__((section(".noinit.rs_p7")));
|
||||
|
||||
static bool rs_p7_peripheral_rate(uint32_t pclk_hz) {
|
||||
const rs_timer_config_t config = {.mode = RS_TIMER_MODE_FREE_RUNNING,
|
||||
.direction = RS_TIMER_DIRECTION_UP};
|
||||
const volatile uint32_t *pwm_rate =
|
||||
(const volatile uint32_t *)(RS_SOC_APB4_PWM_BASE + PWM_CLOCK_HZ_OFFSET);
|
||||
uint32_t first, last;
|
||||
uint64_t start, end;
|
||||
uint64_t expected;
|
||||
rs_timeout_t budget = RS_TIMEOUT_DEFAULT;
|
||||
if (*pwm_rate != pclk_hz || rs_timer_configure(RS_TIMER_0, &config) != RS_OK ||
|
||||
rs_timer_start(RS_TIMER_0) != RS_OK || rs_clint_get_time(&start) != RS_OK ||
|
||||
rs_timer_get_value(RS_TIMER_0, &first) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if (rs_clint_get_time(&end) != RS_OK || budget-- == 0U) {
|
||||
return false;
|
||||
}
|
||||
} while (end - start < 200U);
|
||||
if (rs_timer_get_value(RS_TIMER_0, &last) != RS_OK || rs_timer_stop(RS_TIMER_0) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
expected = (end - start) * (pclk_hz / 1000000U);
|
||||
/* Independent CLINT reference; allow the bounded APB/software read skew.
|
||||
* A wrong /2 or /4 domain cannot fit this +/-25% interval. */
|
||||
return (uint64_t)(last - first) > expected * 3U / 4U &&
|
||||
(uint64_t)(last - first) < expected * 5U / 4U;
|
||||
}
|
||||
|
||||
static bool rs_p7_sleep(void) {
|
||||
rs_dma_session_t session;
|
||||
rs_dma_config_t config = {.kind = RS_DMA_KIND_MM_TO_MM,
|
||||
.request = RS_DMA_REQUEST_SOFTWARE,
|
||||
.source = (uintptr_t)rs_p7_source,
|
||||
.destination = (uintptr_t)rs_p7_destination,
|
||||
.byte_count = sizeof(rs_p7_source),
|
||||
.width = RS_DMA_WIDTH_32,
|
||||
.source_increment = true,
|
||||
.destination_increment = true,
|
||||
.burst_beats = 16U};
|
||||
uint64_t now;
|
||||
uint32_t index;
|
||||
__disable_irq();
|
||||
for (index = 0U; index < 1024U; index++) {
|
||||
rs_p7_source[index] = index ^ UINT32_C(0x13572468);
|
||||
rs_p7_destination[index] = 0U;
|
||||
}
|
||||
if (rs_tiny_rcu_apply_gate(1U, RS_TIMEOUT_DEFAULT) != RS_OK ||
|
||||
rs_dma_session_acquire(&session, RS_DMA_CHANNEL_BULK) != RS_OK ||
|
||||
rs_dma_session_configure(&session, &config) != RS_OK || rs_clint_get_time(&now) != RS_OK ||
|
||||
rs_clint_set_compare(0U, now + 3000U) != RS_OK || rs_dma_session_start(&session) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
__RV_CSR_SET(CSR_MIE, MIE_MTIE);
|
||||
__WFI();
|
||||
__RV_CSR_CLEAR(CSR_MIE, MIE_MTIE);
|
||||
if (rs_clint_set_compare(0U, UINT64_MAX) != RS_OK ||
|
||||
rs_dma_wait(RS_DMA_CHANNEL_BULK, RS_TIMEOUT_DEFAULT) != RS_OK ||
|
||||
rs_dma_session_release(&session) != RS_OK ||
|
||||
rs_tiny_rcu_apply_gate(0U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
return false;
|
||||
}
|
||||
for (index = 0U; index < 1024U; index++) {
|
||||
if (rs_p7_destination[index] != rs_p7_source[index]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rs_p7_profile(rs_tiny_rcu_profile_t profile, uint32_t sys_hz, uint32_t mem_hz,
|
||||
uint32_t pclk_hz) {
|
||||
rs_tiny_rcu_snapshot_t snapshot;
|
||||
uint32_t index;
|
||||
uint64_t before, after;
|
||||
|
||||
if (rs_clint_get_time(&before) != RS_OK ||
|
||||
rs_tiny_rcu_request_profile(profile, RS_TIMEOUT_DEFAULT) != RS_OK ||
|
||||
rs_clint_get_time(&after) != RS_OK || after <= before) {
|
||||
return false;
|
||||
}
|
||||
if (rs_tiny_rcu_get_snapshot(&snapshot) != RS_OK || snapshot.current_profile != profile ||
|
||||
snapshot.sys_hz != sys_hz || snapshot.mem_hz != mem_hz || snapshot.pclk_hz != pclk_hz) {
|
||||
return false;
|
||||
}
|
||||
for (index = 0U; index < 128U; index++) {
|
||||
if (rs_p7_words[index] != (UINT32_C(0xABCDEF00) ^ index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return rs_p7_peripheral_rate(pclk_hz);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
rs_tiny_rcu_snapshot_t snapshot;
|
||||
uint32_t index;
|
||||
uint8_t code = 0U;
|
||||
|
||||
if (rs_tiny_rcu_get_snapshot(&snapshot) == RS_OK && (snapshot.reset_cause & 2U) != 0U) {
|
||||
code = (rs_p7_retained == UINT32_C(0x7037CAFE) && snapshot.current_profile == 0U &&
|
||||
snapshot.sys_hz == 24000000U && snapshot.gate_status == 0U)
|
||||
? 0U
|
||||
: 11U;
|
||||
rs_sysctrl_write_test_status(code == 0U, code);
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0U; index < 128U; index++) {
|
||||
rs_p7_words[index] = UINT32_C(0xABCDEF00) ^ index;
|
||||
}
|
||||
if (rs_tiny_rcu_get_snapshot(&snapshot) != RS_OK || snapshot.sys_hz != 24000000U ||
|
||||
snapshot.target_capability != UINT32_C(0x3FFF)) {
|
||||
code = 1U;
|
||||
} else if ((snapshot.capability & UINT32_C(0xC)) == UINT32_C(0xC)) {
|
||||
if (!rs_p7_profile(RS_TINY_RCU_PROFILE_PLL192, 192000000U, 96000000U, 48000000U)) {
|
||||
code = 2U;
|
||||
} else if (!rs_p7_profile(RS_TINY_RCU_PROFILE_PLL240, 240000000U, 120000000U, 60000000U)) {
|
||||
code = 3U;
|
||||
}
|
||||
} else if (!rs_p7_profile(RS_TINY_RCU_PROFILE_XIN, snapshot.xin_hz, snapshot.xin_hz,
|
||||
snapshot.xin_hz > 60000000U ? snapshot.xin_hz / 2U
|
||||
: snapshot.xin_hz)) {
|
||||
code = 4U;
|
||||
} else {
|
||||
/* No-PLL compatibility has no PLL profile bit. */
|
||||
}
|
||||
if (code == 0U && !rs_p7_profile(RS_TINY_RCU_PROFILE_SAFE24, 24000000U, 24000000U, 24000000U)) {
|
||||
code = 5U;
|
||||
}
|
||||
if (code == 0U && rs_tiny_rcu_apply_gate(UINT32_C(1) << 4U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
code = 6U;
|
||||
}
|
||||
if (code == 0U && rs_tiny_rcu_apply_gate(0U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
code = 7U;
|
||||
}
|
||||
if (code == 0U && rs_tiny_rcu_apply_reset(UINT32_C(1) << 4U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
code = 8U;
|
||||
}
|
||||
if (code == 0U && !rs_p7_sleep()) {
|
||||
code = 9U;
|
||||
}
|
||||
if (code == 0U) {
|
||||
rs_p7_retained = UINT32_C(0x7037CAFE);
|
||||
(void)rs_tiny_rcu_system_reset(RS_TIMEOUT_DEFAULT);
|
||||
code = 10U;
|
||||
}
|
||||
rs_sysctrl_write_test_status(code == 0U, code);
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
+12
-5
@@ -78,15 +78,22 @@ for the matrix and its pending/current evidence boundary.
|
||||
|
||||
The [2026-10-07 Tiny refreeze](../docs/ip/tiny-soc.md#ics55-default-platform-and-final-timing-gate-2026-10-07)
|
||||
sets the default to ICS55 with `HAVE_PLL=YES` and SAFE24 boot.
|
||||
`ci/ics55-tiny.mk` implements that entrypoint with the PLL held off; standalone
|
||||
PLL backend tests do not enable RCU/SYS switching. `make SOC=TINY` selects this
|
||||
`ci/ics55-tiny.mk` boots with the PLL held off; R2-P7 adds explicit software
|
||||
requests for functional PLL192/240 transitions, subject to separate acceptance.
|
||||
`ci/ihp130-tiny-xin48.mk` and `ci/ihp130-tiny-xin96.mk` normalize their declared
|
||||
external input to REF24 at boot and permit no-PLL XIN transitions. See the
|
||||
[P7 runbook](../docs/ip/tiny-soc-r2-clock-reset.md) for the evidence boundary.
|
||||
`TINY_P7_ACCEPTANCE=YES APP=ci_smoke` selects the distinct RCU acceptance image
|
||||
and configuration digest; ordinary Tiny acceptance firmware remains the default.
|
||||
`make SOC=TINY` selects this
|
||||
committed profile, and `make SOC=TINY PDK=IHP130` selects explicit compatibility.
|
||||
Do not substitute Mini's `ci/ics55.mk` for Tiny. Acceptance evidence belongs in
|
||||
the Tiny ledger, and physical qualification remains pending.
|
||||
|
||||
`ci/ihp130-tiny.mk` selects `SOC=TINY`, one RV32IMC Hazard3 (A disabled),
|
||||
128 KiB SRAM, AXI32/APB4, four DMA channels and the wired peripheral subset.
|
||||
128 KiB SRAM and AXI32/APB4. The P6 candidate adds eight-channel DMA and the
|
||||
frozen shared-peripheral integration; source presence is not phase acceptance.
|
||||
The profile uses 24 MHz, `HAVE_HP=NO`, `MINI_MODE=NONE`, CSR-enabled RV32IM
|
||||
firmware and `ld2_all_sram`. Both `bringup` and `ci_smoke` select Tiny acceptance
|
||||
firmware. Icarus and Verilator use the same pin-level Flash model. Other PDKs,
|
||||
wireless, external RAM and HP applications are rejected by the Tiny config gate.
|
||||
firmware. Icarus and Verilator use the same pin-level Flash model. PDKs other
|
||||
than IHP130/ICS55, external-RAM boot layouts and HP applications remain rejected.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Functional external-input profile; physical qualification is pending.
|
||||
SOC := TINY
|
||||
MINI_MODE := NONE
|
||||
PDK := IHP130
|
||||
SIMU := VERILATOR
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 128
|
||||
HAVE_HP := NO
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 48000000
|
||||
AUD_CLK_HZ := 24000000
|
||||
CLINT_TIMEBASE_HZ := 1000000
|
||||
ISA := RV32IM
|
||||
HAVE_CSR := YES
|
||||
APP := bringup
|
||||
LINK_TYPE := ld2_all_sram
|
||||
RTL_TOP := retrosoc_tiny_tb
|
||||
@@ -0,0 +1,19 @@
|
||||
# Functional external-input profile; physical qualification is pending.
|
||||
SOC := TINY
|
||||
MINI_MODE := NONE
|
||||
PDK := IHP130
|
||||
SIMU := VERILATOR
|
||||
HAVE_PLL := NO
|
||||
HAVE_SRAM_IF := YES
|
||||
HAVE_SRAM_MACRO := YES
|
||||
SRAM_SIZE_KIB := 128
|
||||
HAVE_HP := NO
|
||||
HAVE_SVA := NO
|
||||
EXT_CLK_HZ := 96000000
|
||||
AUD_CLK_HZ := 24000000
|
||||
CLINT_TIMEBASE_HZ := 1000000
|
||||
ISA := RV32IM
|
||||
HAVE_CSR := YES
|
||||
APP := bringup
|
||||
LINK_TYPE := ld2_all_sram
|
||||
RTL_TOP := retrosoc_tiny_tb
|
||||
+6
-1
@@ -239,11 +239,16 @@ For the complete firmware, simulation, synthesis, and timing flow, see the
|
||||
|
||||
Tiny uses the same `rs_` SDK and selects its generated memory, IRQ and capability
|
||||
headers through the committed profile. The generated memory-map header includes
|
||||
Tiny capability metadata, so public DMA headers report four channels without
|
||||
Tiny capability metadata, so public DMA headers report eight channels without
|
||||
requiring an application to reproduce private compiler flags. Unavailable IP
|
||||
drivers are omitted; Tiny SYSCTRL rejects unsupported lifecycle/PLL operations
|
||||
before MMIO. Startup skips external-RAM initialization and loads into SRAM.
|
||||
|
||||
P6 selects the existing RNG/CRC/WS2812/Crypto/I2S/SDIO drivers. Crypto uses 4/5,
|
||||
audio uses 6/7 and channel 3 remains exclusively leased for a WS frame.
|
||||
I2C1, SDIO1, DVP and future DMA endpoints remain unsupported on Tiny. Shared
|
||||
Mini defaults are unchanged; Tiny does not acquire Mini's HP channel reservation.
|
||||
|
||||
`<retrosoc/hal/watchdog.h>` provides `rs_watchdog_configure`, `rs_watchdog_start`,
|
||||
`rs_watchdog_service`, `rs_watchdog_get_status` and `rs_watchdog_clear_reset_cause`,
|
||||
with SDK status values and bounded command waits. These wrappers preserve the
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef enum {
|
||||
RS_EIO = -5,
|
||||
RS_ENOTSUP = -6,
|
||||
RS_EFORMAT = -7,
|
||||
RS_EBUSY = -8,
|
||||
} rs_status_t;
|
||||
|
||||
typedef uint32_t rs_timeout_t;
|
||||
|
||||
@@ -50,6 +50,15 @@ typedef enum {
|
||||
RS_DMA_CHANNEL_BULK = 3,
|
||||
RS_DMA_CHANNEL_CRYPTO_IN = 4,
|
||||
RS_DMA_CHANNEL_CRYPTO_OUT = 5,
|
||||
#ifdef RS_SOC_TINY
|
||||
RS_DMA_CHANNEL_DVP = 2,
|
||||
RS_DMA_CHANNEL_I2S_TX = 6,
|
||||
RS_DMA_CHANNEL_I2S_RX = 7,
|
||||
#else
|
||||
RS_DMA_CHANNEL_DVP = RS_DMA_CHANNEL_BULK,
|
||||
RS_DMA_CHANNEL_I2S_TX = RS_DMA_CHANNEL_BULK,
|
||||
RS_DMA_CHANNEL_I2S_RX = RS_DMA_CHANNEL_BULK,
|
||||
#endif
|
||||
} rs_dma_channel_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -77,13 +77,11 @@
|
||||
#define RS_DMA_ERROR_READ UINT32_C(0x00000040)
|
||||
#define RS_DMA_ERROR_STREAM_LAST UINT32_C(0x00000100)
|
||||
|
||||
#ifdef RS_SOC_TINY
|
||||
#define RS_DMA_CHANNEL_COUNT 4U
|
||||
#else
|
||||
#define RS_DMA_CHANNEL_COUNT 8U
|
||||
#endif
|
||||
#ifndef RS_SOC_TINY
|
||||
#define RS_DMA_CHANNEL_HP 6U
|
||||
#define RS_DMA_CHANNEL_RESERVED 7U
|
||||
#endif
|
||||
#define RS_DMA_MAX_BURST_BEATS 16U
|
||||
#define RS_DMA_DATA_WIDTH_BITS 32U
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef RETROSOC_HAL_RCU_H
|
||||
#define RETROSOC_HAL_RCU_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
typedef enum {
|
||||
RS_TINY_RCU_PROFILE_SAFE24 = 0,
|
||||
RS_TINY_RCU_PROFILE_XIN = 1,
|
||||
RS_TINY_RCU_PROFILE_PLL192 = 2,
|
||||
RS_TINY_RCU_PROFILE_PLL240 = 3,
|
||||
} rs_tiny_rcu_profile_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t capability;
|
||||
uint32_t target_capability;
|
||||
uint32_t status;
|
||||
uint32_t fault;
|
||||
uint32_t reset_cause;
|
||||
uint32_t gate_status;
|
||||
uint32_t xin_hz;
|
||||
uint32_t ref_hz;
|
||||
uint32_t sys_hz;
|
||||
uint32_t mem_hz;
|
||||
uint32_t pclk_hz;
|
||||
uint32_t clint_hz;
|
||||
rs_tiny_rcu_profile_t current_profile;
|
||||
} rs_tiny_rcu_snapshot_t;
|
||||
|
||||
rs_status_t rs_tiny_rcu_get_snapshot(rs_tiny_rcu_snapshot_t *snapshot);
|
||||
rs_status_t rs_tiny_rcu_profile_hz(rs_tiny_rcu_profile_t profile, uint32_t *hz);
|
||||
rs_status_t rs_tiny_rcu_request_profile(rs_tiny_rcu_profile_t profile, rs_timeout_t timeout);
|
||||
rs_status_t rs_tiny_rcu_apply_gate(uint32_t target_mask, rs_timeout_t timeout);
|
||||
rs_status_t rs_tiny_rcu_apply_reset(uint32_t target_mask, rs_timeout_t timeout);
|
||||
rs_status_t rs_tiny_rcu_clear_fault(uint32_t mask);
|
||||
rs_status_t rs_tiny_rcu_clear_reset_cause(uint32_t mask);
|
||||
rs_status_t rs_tiny_rcu_system_reset(rs_timeout_t timeout);
|
||||
rs_status_t rs_tiny_rcu_set_clkout(uint32_t source, uint16_t half_period);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef RETROSOC_HAL_RCU_REGS_H
|
||||
#define RETROSOC_HAL_RCU_REGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define RS_TINY_RCU_ID_OFFSET UINT32_C(0x100)
|
||||
#define RS_TINY_RCU_VERSION_OFFSET UINT32_C(0x104)
|
||||
#define RS_TINY_RCU_CAPABILITY_OFFSET UINT32_C(0x108)
|
||||
#define RS_TINY_RCU_CLOCK_REQUEST_OFFSET UINT32_C(0x10C)
|
||||
#define RS_TINY_RCU_CLOCK_CURRENT_OFFSET UINT32_C(0x110)
|
||||
#define RS_TINY_RCU_COMMAND_OFFSET UINT32_C(0x114)
|
||||
#define RS_TINY_RCU_STATUS_OFFSET UINT32_C(0x118)
|
||||
#define RS_TINY_RCU_TIMEOUT_OFFSET UINT32_C(0x11C)
|
||||
#define RS_TINY_RCU_GATE_REQUEST_OFFSET UINT32_C(0x120)
|
||||
#define RS_TINY_RCU_GATE_STATUS_OFFSET UINT32_C(0x124)
|
||||
#define RS_TINY_RCU_RESET_REQUEST_OFFSET UINT32_C(0x128)
|
||||
#define RS_TINY_RCU_RESET_DONE_OFFSET UINT32_C(0x12C)
|
||||
#define RS_TINY_RCU_RESET_CAUSE_OFFSET UINT32_C(0x130)
|
||||
#define RS_TINY_RCU_FAULT_OFFSET UINT32_C(0x134)
|
||||
#define RS_TINY_RCU_IRQ_STATE_OFFSET UINT32_C(0x138)
|
||||
#define RS_TINY_RCU_IRQ_ENABLE_OFFSET UINT32_C(0x13C)
|
||||
#define RS_TINY_RCU_XIN_HZ_OFFSET UINT32_C(0x140)
|
||||
#define RS_TINY_RCU_REF_HZ_OFFSET UINT32_C(0x144)
|
||||
#define RS_TINY_RCU_SYS_HZ_OFFSET UINT32_C(0x148)
|
||||
#define RS_TINY_RCU_MEM_HZ_OFFSET UINT32_C(0x14C)
|
||||
#define RS_TINY_RCU_PCLK_HZ_OFFSET UINT32_C(0x150)
|
||||
#define RS_TINY_RCU_CLINT_HZ_OFFSET UINT32_C(0x154)
|
||||
#define RS_TINY_RCU_TARGET_CAP_OFFSET UINT32_C(0x158)
|
||||
#define RS_TINY_RCU_CLKOUT_OFFSET UINT32_C(0x15C)
|
||||
|
||||
#define RS_TINY_RCU_COMMAND_CLOCK_APPLY UINT32_C(1U << 0)
|
||||
#define RS_TINY_RCU_COMMAND_GATE_APPLY UINT32_C(1U << 1)
|
||||
#define RS_TINY_RCU_COMMAND_RESET_APPLY UINT32_C(1U << 2)
|
||||
#define RS_TINY_RCU_COMMAND_SYSTEM_RESET UINT32_C(1U << 3)
|
||||
#define RS_TINY_RCU_STATUS_BUSY UINT32_C(1U << 0)
|
||||
#define RS_TINY_RCU_STATUS_SAFE_SOURCE UINT32_C(1U << 1)
|
||||
#define RS_TINY_RCU_STATUS_PLL_LOCKED UINT32_C(1U << 2)
|
||||
#define RS_TINY_RCU_STATUS_PLL_SELECTED UINT32_C(1U << 3)
|
||||
#define RS_TINY_RCU_STATUS_FAULT UINT32_C(1U << 4)
|
||||
#define RS_TINY_RCU_CAP_PLL_PRESENT UINT32_C(1U << 8)
|
||||
#define RS_TINY_RCU_CAP_TARGET_MASK UINT32_C(0x0003FFFF)
|
||||
#define RS_TINY_RCU_FAULT_MASK UINT32_C(0x0000001F)
|
||||
#define RS_TINY_RCU_RESET_CAUSE_MASK UINT32_C(0x0000003F)
|
||||
#define RS_TINY_RCU_CSR_MSLEEP 0xBF0
|
||||
|
||||
#endif
|
||||
+23
-7
@@ -5,16 +5,25 @@
|
||||
|
||||
static const rs_dma_session_t *rs_dma_owners[RS_DMA_CHANNEL_COUNT];
|
||||
|
||||
#ifdef RS_DMA_TEST_MMIO
|
||||
uint32_t rs_dma_test_irq_save(void);
|
||||
void rs_dma_test_irq_restore(uint32_t saved);
|
||||
#endif
|
||||
|
||||
static uint32_t rs_dma_lock(void) {
|
||||
uint32_t saved = 0U;
|
||||
#if defined(__riscv) && defined(CSR_ENABLE)
|
||||
#ifdef RS_DMA_TEST_MMIO
|
||||
saved = rs_dma_test_irq_save();
|
||||
#elif defined(__riscv) && defined(CSR_ENABLE)
|
||||
__asm__ volatile("csrrci %0, mstatus, 8" : "=r"(saved)::"memory");
|
||||
#endif
|
||||
return saved;
|
||||
}
|
||||
|
||||
static void rs_dma_unlock(uint32_t saved) {
|
||||
#if defined(__riscv) && defined(CSR_ENABLE)
|
||||
#ifdef RS_DMA_TEST_MMIO
|
||||
rs_dma_test_irq_restore(saved);
|
||||
#elif defined(__riscv) && defined(CSR_ENABLE)
|
||||
if ((saved & UINT32_C(8)) != 0U) {
|
||||
__asm__ volatile("csrsi mstatus, 8" ::: "memory");
|
||||
}
|
||||
@@ -185,6 +194,7 @@ rs_status_t rs_dma_submit_tcd_chain(uint32_t channel, rs_dma_tcd_t *first, uint3
|
||||
rs_status_t result;
|
||||
uint32_t control;
|
||||
uint32_t burst;
|
||||
uint32_t saved;
|
||||
|
||||
result = rs_dma_tcd_validate(channel, current);
|
||||
if (result != RS_OK) {
|
||||
@@ -208,14 +218,20 @@ rs_status_t rs_dma_submit_tcd_chain(uint32_t channel, rs_dma_tcd_t *first, uint3
|
||||
config.crc_expected = current->crc_expected;
|
||||
config.priority = (uint8_t)((control >> RS_DMA_TCD_PRIORITY_SHIFT) & UINT32_C(0x3));
|
||||
config.burst_beats = (uint8_t)burst;
|
||||
/* Publish configuration, TCD and START before an ISR can lease the
|
||||
* idle channel. Nested helpers preserve this outer interrupt mask.
|
||||
* Restore interrupts before the bounded completion wait. */
|
||||
saved = rs_dma_lock();
|
||||
result = rs_dma_configure(channel, &config);
|
||||
if (result != RS_OK) {
|
||||
rs_dma_unlock(saved);
|
||||
return result;
|
||||
}
|
||||
RS_DMA_CH_REG(channel, RS_DMA_CH_REG_TCD_HEAD) = (uint32_t)(uintptr_t)current;
|
||||
RS_DMA_CH_REG(channel, RS_DMA_CH_REG_TCD_COUNT) = UINT32_C(1);
|
||||
rs_dma_fence();
|
||||
result = rs_dma_start(channel);
|
||||
rs_dma_unlock(saved);
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -411,9 +427,9 @@ void ip_dma_test(void) {
|
||||
.lowbound = 32U,
|
||||
}) != RS_OK) ||
|
||||
(rs_i2s_enable(true, false) != RS_OK) ||
|
||||
(rs_dma_configure(RS_DMA_CHANNEL_BULK, &tx_config) != RS_OK) ||
|
||||
(rs_dma_configure(RS_DMA_CHANNEL_I2S_TX, &tx_config) != RS_OK) ||
|
||||
(rs_dma_start(RS_DMA_CHANNEL_BULK) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_BULK, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_I2S_TX, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
printf("dma transmit failed\n");
|
||||
return;
|
||||
}
|
||||
@@ -432,9 +448,9 @@ void ip_dma_test(void) {
|
||||
.lowbound = 32U,
|
||||
}) != RS_OK) ||
|
||||
(rs_i2s_enable(false, true) != RS_OK) ||
|
||||
(rs_dma_configure(RS_DMA_CHANNEL_BULK, &rx_config) != RS_OK) ||
|
||||
(rs_dma_start(RS_DMA_CHANNEL_BULK) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_BULK, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
(rs_dma_configure(RS_DMA_CHANNEL_I2S_RX, &rx_config) != RS_OK) ||
|
||||
(rs_dma_start(RS_DMA_CHANNEL_I2S_RX) != RS_OK) ||
|
||||
(rs_dma_wait(RS_DMA_CHANNEL_I2S_RX, RS_TIMEOUT_DEFAULT) != RS_OK)) {
|
||||
printf("dma receive failed\n");
|
||||
(void)rs_i2s_disable();
|
||||
return;
|
||||
|
||||
@@ -19,7 +19,8 @@ static bool rs_dma_address_valid(uintptr_t address, uint32_t byte_count, bool in
|
||||
|
||||
static bool rs_dma_request_valid(const rs_dma_config_t *config) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (config->kind != RS_DMA_KIND_MM_TO_MM) {
|
||||
if (((uint32_t)config->request >= 16U) ||
|
||||
((UINT32_C(0x31FF) & (UINT32_C(1) << (uint32_t)config->request)) == 0U)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -97,7 +98,7 @@ rs_status_t rs_dma_tcd_validate(uint32_t channel, const rs_dma_tcd_t *tcd) {
|
||||
request = (tcd->control >> RS_DMA_TCD_REQUEST_SHIFT) & UINT32_C(0xF);
|
||||
burst = (tcd->control >> RS_DMA_TCD_BURST_SHIFT) & UINT32_C(0x1F);
|
||||
#ifdef RS_SOC_TINY
|
||||
if (kind != (uint32_t)RS_DMA_KIND_MM_TO_MM) {
|
||||
if ((UINT32_C(0x31FF) & (UINT32_C(1) << request)) == 0U) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -49,8 +49,12 @@
|
||||
#define RS_I2C_TIMEOUT_MAX_CYCLES UINT32_C(0xFFFFFF)
|
||||
|
||||
static uintptr_t rs_i2c_base(rs_i2c_bus_t bus) {
|
||||
#ifdef RS_SOC_TINY
|
||||
return (bus == RS_I2C_BUS_0) ? (uintptr_t)RS_SOC_APB4_I2C0_BASE : (uintptr_t)0U;
|
||||
#else
|
||||
return (bus == RS_I2C_BUS_0) ? (uintptr_t)RS_SOC_APB4_I2C0_BASE
|
||||
: (uintptr_t)RS_SOC_APB4_I2C1_BASE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool rs_i2c_bus_valid(rs_i2c_bus_t bus) {
|
||||
@@ -92,8 +96,13 @@ static rs_status_t rs_i2c_gpio_configure(rs_i2c_bus_t bus) {
|
||||
.filter_enable = false,
|
||||
.interrupt_enable = false,
|
||||
};
|
||||
#ifdef RS_SOC_TINY
|
||||
const uint32_t scl_pin = UINT32_C(10);
|
||||
const uint32_t sda_pin = UINT32_C(11);
|
||||
#else
|
||||
const uint32_t scl_pin = (bus == RS_I2C_BUS_0) ? UINT32_C(7) : UINT32_C(3);
|
||||
const uint32_t sda_pin = (bus == RS_I2C_BUS_0) ? UINT32_C(8) : UINT32_C(4);
|
||||
#endif
|
||||
rs_status_t status = rs_gpio_configure(scl_pin, &pin_config);
|
||||
|
||||
if (status == RS_OK) {
|
||||
@@ -228,6 +237,11 @@ static rs_status_t rs_i2c_wait_done(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
|
||||
rs_status_t rs_i2c_configure(rs_i2c_bus_t bus, const rs_i2c_config_t *config,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_i2c_timing_t timing;
|
||||
uint32_t stretch_timeout;
|
||||
uint32_t bus_idle_timeout;
|
||||
@@ -287,6 +301,11 @@ rs_status_t rs_i2c_configure(rs_i2c_bus_t bus, const rs_i2c_config_t *config,
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_init(rs_i2c_bus_t bus, uint32_t source_clock_hz, uint32_t bus_hz) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
const rs_i2c_config_t config = {
|
||||
.source_clock_hz = source_clock_hz,
|
||||
.bus_hz = bus_hz,
|
||||
@@ -303,6 +322,11 @@ rs_status_t rs_i2c_init(rs_i2c_bus_t bus, uint32_t source_clock_hz, uint32_t bus
|
||||
|
||||
rs_status_t rs_i2c_transfer(rs_i2c_bus_t bus, const rs_i2c_transfer_t *transfer,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (transfer == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -338,6 +362,11 @@ static rs_status_t rs_i2c_register_prefix(const rs_i2c_register_access_t *access
|
||||
|
||||
rs_status_t rs_i2c_register_write(rs_i2c_bus_t bus, const rs_i2c_register_access_t *access,
|
||||
const uint8_t *data, size_t length, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint8_t prefix[2];
|
||||
size_t prefix_length;
|
||||
rs_status_t status;
|
||||
@@ -355,6 +384,11 @@ rs_status_t rs_i2c_register_write(rs_i2c_bus_t bus, const rs_i2c_register_access
|
||||
|
||||
rs_status_t rs_i2c_register_read(rs_i2c_bus_t bus, const rs_i2c_register_access_t *access,
|
||||
uint8_t *data, size_t length, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint8_t prefix[2];
|
||||
size_t prefix_length;
|
||||
rs_status_t status;
|
||||
@@ -371,6 +405,11 @@ rs_status_t rs_i2c_register_read(rs_i2c_bus_t bus, const rs_i2c_register_access_
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_abort(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_i2c_bus_valid(bus)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -382,6 +421,11 @@ rs_status_t rs_i2c_abort(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_recover(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus)) {
|
||||
@@ -408,6 +452,11 @@ rs_status_t rs_i2c_recover(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_get_status(rs_i2c_bus_t bus, rs_i2c_status_t *status) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t levels;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus) || (status == NULL)) {
|
||||
@@ -423,6 +472,11 @@ rs_status_t rs_i2c_get_status(rs_i2c_bus_t bus, rs_i2c_status_t *status) {
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_irq_enable(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_i2c_bus_valid(bus) || ((mask & ~RS_I2C_INTR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -431,6 +485,11 @@ rs_status_t rs_i2c_irq_enable(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_irq_ack(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_i2c_bus_valid(bus) || (mask == 0U) || ((mask & ~RS_I2C_INTR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -439,6 +498,11 @@ rs_status_t rs_i2c_irq_ack(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_irq_test(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_i2c_bus_valid(bus) || (mask == 0U) || ((mask & ~RS_I2C_INTR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -449,6 +513,11 @@ rs_status_t rs_i2c_irq_test(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
rs_status_t rs_i2c_write_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address,
|
||||
const uint8_t *data, size_t length, rs_i2c_dma_workspace_t *workspace,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
size_t index;
|
||||
const uint32_t channel = (bus == RS_I2C_BUS_0) ? RS_DMA_CHANNEL_I2C0 : RS_DMA_CHANNEL_I2C1;
|
||||
@@ -494,6 +563,11 @@ rs_status_t rs_i2c_write_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_ad
|
||||
rs_status_t rs_i2c_read_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address, uint8_t *data,
|
||||
size_t length, rs_i2c_dma_workspace_t *workspace,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (bus == RS_I2C_BUS_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
size_t index;
|
||||
const uint32_t channel = (bus == RS_I2C_BUS_0) ? RS_DMA_CHANNEL_I2C0 : RS_DMA_CHANNEL_I2C1;
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/rcu.h>
|
||||
#include <retrosoc/hal/rcu_regs.h>
|
||||
#if defined(__riscv) && defined(RS_SOC_TINY)
|
||||
#include <retrosoc/arch/riscv/system_base.h>
|
||||
#endif
|
||||
|
||||
static volatile uint32_t *rs_tiny_rcu_register(uint32_t offset) {
|
||||
#if defined(RS_TINY_RCU_TEST_MMIO)
|
||||
extern volatile uint32_t rs_tiny_rcu_test_mmio[1024];
|
||||
return &rs_tiny_rcu_test_mmio[offset / 4U];
|
||||
#else
|
||||
return (volatile uint32_t *)(RS_SOC_APB4_SYSCTRL_BASE + (uintptr_t)offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
static rs_status_t rs_tiny_rcu_fault_status(void) {
|
||||
const uint32_t fault = *rs_tiny_rcu_register(RS_TINY_RCU_FAULT_OFFSET);
|
||||
if ((fault & UINT32_C(0x09)) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
return (fault != 0U) ? RS_ETIMEOUT : RS_OK;
|
||||
}
|
||||
|
||||
static rs_status_t rs_tiny_rcu_prepare(rs_timeout_t timeout) {
|
||||
if (timeout == 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((*rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET) & RS_TINY_RCU_STATUS_BUSY) != 0U) {
|
||||
return RS_EBUSY;
|
||||
}
|
||||
/* The caller owns clearing sticky faults. Do not start an operation whose
|
||||
* result could be confused with a previous failure. */
|
||||
return rs_tiny_rcu_fault_status();
|
||||
}
|
||||
|
||||
static rs_status_t rs_tiny_rcu_wait(rs_timeout_t timeout, uint32_t *status) {
|
||||
uint32_t value = 0U;
|
||||
|
||||
while (timeout-- != 0U) {
|
||||
value = *rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET);
|
||||
if ((value & RS_TINY_RCU_STATUS_BUSY) == 0U) {
|
||||
if (status != NULL) {
|
||||
*status = value;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_get_snapshot(rs_tiny_rcu_snapshot_t *snapshot) {
|
||||
uint32_t initial_profile;
|
||||
if (snapshot == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((*rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET) & RS_TINY_RCU_STATUS_BUSY) != 0U) {
|
||||
return RS_EBUSY;
|
||||
}
|
||||
initial_profile = *rs_tiny_rcu_register(RS_TINY_RCU_CLOCK_CURRENT_OFFSET);
|
||||
snapshot->capability = *rs_tiny_rcu_register(RS_TINY_RCU_CAPABILITY_OFFSET);
|
||||
snapshot->target_capability = *rs_tiny_rcu_register(RS_TINY_RCU_TARGET_CAP_OFFSET);
|
||||
snapshot->status = *rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET);
|
||||
snapshot->fault = *rs_tiny_rcu_register(RS_TINY_RCU_FAULT_OFFSET);
|
||||
snapshot->reset_cause = *rs_tiny_rcu_register(RS_TINY_RCU_RESET_CAUSE_OFFSET);
|
||||
snapshot->gate_status = *rs_tiny_rcu_register(RS_TINY_RCU_GATE_STATUS_OFFSET);
|
||||
snapshot->xin_hz = *rs_tiny_rcu_register(RS_TINY_RCU_XIN_HZ_OFFSET);
|
||||
snapshot->ref_hz = *rs_tiny_rcu_register(RS_TINY_RCU_REF_HZ_OFFSET);
|
||||
snapshot->sys_hz = *rs_tiny_rcu_register(RS_TINY_RCU_SYS_HZ_OFFSET);
|
||||
snapshot->mem_hz = *rs_tiny_rcu_register(RS_TINY_RCU_MEM_HZ_OFFSET);
|
||||
snapshot->pclk_hz = *rs_tiny_rcu_register(RS_TINY_RCU_PCLK_HZ_OFFSET);
|
||||
snapshot->clint_hz = *rs_tiny_rcu_register(RS_TINY_RCU_CLINT_HZ_OFFSET);
|
||||
snapshot->current_profile =
|
||||
(rs_tiny_rcu_profile_t)(*rs_tiny_rcu_register(RS_TINY_RCU_CLOCK_CURRENT_OFFSET) &
|
||||
UINT32_C(3));
|
||||
if (((*rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET) & RS_TINY_RCU_STATUS_BUSY) != 0U) ||
|
||||
((uint32_t)snapshot->current_profile != initial_profile)) {
|
||||
return RS_EBUSY;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_profile_hz(rs_tiny_rcu_profile_t profile, uint32_t *hz) {
|
||||
if (hz == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
switch (profile) {
|
||||
case RS_TINY_RCU_PROFILE_SAFE24:
|
||||
*hz = UINT32_C(24000000);
|
||||
break;
|
||||
case RS_TINY_RCU_PROFILE_XIN:
|
||||
*hz = *rs_tiny_rcu_register(RS_TINY_RCU_XIN_HZ_OFFSET);
|
||||
break;
|
||||
case RS_TINY_RCU_PROFILE_PLL192:
|
||||
*hz = UINT32_C(192000000);
|
||||
break;
|
||||
case RS_TINY_RCU_PROFILE_PLL240:
|
||||
*hz = UINT32_C(240000000);
|
||||
break;
|
||||
default:
|
||||
return RS_EINVAL;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_request_profile(rs_tiny_rcu_profile_t profile, rs_timeout_t timeout) {
|
||||
uint32_t capability;
|
||||
uint32_t status;
|
||||
uint32_t hz;
|
||||
rs_status_t result;
|
||||
|
||||
if (timeout == 0U || rs_tiny_rcu_profile_hz(profile, &hz) != RS_OK) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
(void)hz;
|
||||
capability = *rs_tiny_rcu_register(RS_TINY_RCU_CAPABILITY_OFFSET);
|
||||
if ((capability & (UINT32_C(1) << (uint32_t)profile)) == 0U) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
result = rs_tiny_rcu_prepare(timeout);
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_CLOCK_REQUEST_OFFSET) = (uint32_t)profile;
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_COMMAND_OFFSET) = RS_TINY_RCU_COMMAND_CLOCK_APPLY;
|
||||
if (rs_tiny_rcu_wait(timeout, &status) != RS_OK) {
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
if ((status & RS_TINY_RCU_STATUS_FAULT) != 0U) {
|
||||
return rs_tiny_rcu_fault_status();
|
||||
}
|
||||
if (*rs_tiny_rcu_register(RS_TINY_RCU_CLOCK_CURRENT_OFFSET) != (uint32_t)profile) {
|
||||
return RS_EIO;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_apply_gate(uint32_t target_mask, rs_timeout_t timeout) {
|
||||
uint32_t status;
|
||||
rs_status_t result;
|
||||
|
||||
if (timeout == 0U || (target_mask & ~RS_TINY_RCU_CAP_TARGET_MASK) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((target_mask & ~(*rs_tiny_rcu_register(RS_TINY_RCU_TARGET_CAP_OFFSET))) != 0U) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
result = rs_tiny_rcu_prepare(timeout);
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_GATE_REQUEST_OFFSET) = target_mask;
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_COMMAND_OFFSET) = RS_TINY_RCU_COMMAND_GATE_APPLY;
|
||||
if (rs_tiny_rcu_wait(timeout, &status) != RS_OK) {
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
result = rs_tiny_rcu_fault_status();
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
#if defined(__riscv) && defined(RS_SOC_TINY)
|
||||
/* Hazard3's existing sleep permission complements the RCU leaf gate.
|
||||
* Keep power-down clear: the fabric, SRAM and DMA remain available. */
|
||||
if ((target_mask & 1U) != 0U) {
|
||||
__RV_CSR_CLEAR(RS_TINY_RCU_CSR_MSLEEP, 2U);
|
||||
__RV_CSR_SET(RS_TINY_RCU_CSR_MSLEEP, 1U);
|
||||
} else {
|
||||
__RV_CSR_CLEAR(RS_TINY_RCU_CSR_MSLEEP, 1U);
|
||||
}
|
||||
#endif
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_apply_reset(uint32_t target_mask, rs_timeout_t timeout) {
|
||||
uint32_t status;
|
||||
rs_status_t result;
|
||||
|
||||
if (timeout == 0U || target_mask == 0U || (target_mask & ~RS_TINY_RCU_CAP_TARGET_MASK) != 0U ||
|
||||
(target_mask & 1U) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((target_mask & ~(*rs_tiny_rcu_register(RS_TINY_RCU_TARGET_CAP_OFFSET))) != 0U) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
result = rs_tiny_rcu_prepare(timeout);
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
if ((*rs_tiny_rcu_register(RS_TINY_RCU_GATE_STATUS_OFFSET) & target_mask) != 0U) {
|
||||
return RS_EBUSY;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_RESET_REQUEST_OFFSET) = target_mask;
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_COMMAND_OFFSET) = RS_TINY_RCU_COMMAND_RESET_APPLY;
|
||||
if (rs_tiny_rcu_wait(timeout, &status) != RS_OK) {
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
return rs_tiny_rcu_fault_status();
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_clear_fault(uint32_t mask) {
|
||||
if ((mask & ~RS_TINY_RCU_FAULT_MASK) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_FAULT_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_clear_reset_cause(uint32_t mask) {
|
||||
if ((mask & ~RS_TINY_RCU_RESET_CAUSE_MASK) != 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_RESET_CAUSE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_system_reset(rs_timeout_t timeout) {
|
||||
uint32_t status;
|
||||
if (timeout == 0U) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = *rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET);
|
||||
if ((status & RS_TINY_RCU_STATUS_BUSY) != 0U) {
|
||||
return RS_EBUSY;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_COMMAND_OFFSET) = RS_TINY_RCU_COMMAND_SYSTEM_RESET;
|
||||
/* Success restarts execution at the reset vector. Returning means failure. */
|
||||
while (timeout-- != 0U) {
|
||||
status = *rs_tiny_rcu_register(RS_TINY_RCU_STATUS_OFFSET);
|
||||
if ((status & RS_TINY_RCU_STATUS_FAULT) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_tiny_rcu_set_clkout(uint32_t source, uint16_t half_period) {
|
||||
rs_tiny_rcu_snapshot_t snapshot;
|
||||
rs_status_t result;
|
||||
uint32_t hz;
|
||||
if (source > 4U || (source != 0U && half_period == 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
result = rs_tiny_rcu_get_snapshot(&snapshot);
|
||||
if (result != RS_OK) {
|
||||
return result;
|
||||
}
|
||||
hz = source == 2U ? snapshot.sys_hz
|
||||
: source == 3U ? snapshot.mem_hz
|
||||
: source == 4U ? snapshot.pclk_hz
|
||||
: snapshot.ref_hz;
|
||||
if (source != 0U && (uint64_t)hz > (UINT64_C(48000000) * (uint64_t)half_period)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if (source != 0U && (*rs_tiny_rcu_register(RS_TINY_RCU_CLKOUT_OFFSET) & 7U) != 0U) {
|
||||
return RS_EBUSY;
|
||||
}
|
||||
*rs_tiny_rcu_register(RS_TINY_RCU_CLKOUT_OFFSET) = source | ((uint32_t)half_period << 8U);
|
||||
return (*rs_tiny_rcu_register(RS_TINY_RCU_FAULT_OFFSET) != 0U) ? RS_EIO : RS_OK;
|
||||
}
|
||||
+215
-5
@@ -53,6 +53,12 @@
|
||||
RS_SD_R1_CARD_ECC_FAILED | RS_SD_R1_CC_ERROR | RS_SD_R1_ERROR | RS_SD_R1_CSD_OVERWRITE | \
|
||||
RS_SD_R1_WP_ERASE_SKIP)
|
||||
|
||||
/* Preserve protocol ceilings while supporting slower product input clocks. */
|
||||
static uint32_t rs_sdio_transfer_clock(uint32_t source_hz, uint32_t ceiling_hz) {
|
||||
const uint32_t maximum_hz = source_hz / UINT32_C(2);
|
||||
return (maximum_hz < ceiling_hz) ? maximum_hz : ceiling_hz;
|
||||
}
|
||||
|
||||
static bool rs_sdio_instance_valid(rs_sdio_instance_t instance) {
|
||||
return (instance == RS_SDIO_INSTANCE_0) || (instance == RS_SDIO_INSTANCE_1);
|
||||
}
|
||||
@@ -61,8 +67,10 @@ static uintptr_t rs_sdio_base(rs_sdio_instance_t instance) {
|
||||
switch (instance) {
|
||||
case RS_SDIO_INSTANCE_0:
|
||||
return (uintptr_t)RS_SOC_APB4_SDIO0_BASE;
|
||||
#ifndef RS_SOC_TINY
|
||||
case RS_SDIO_INSTANCE_1:
|
||||
return (uintptr_t)RS_SOC_APB4_SDIO1_BASE;
|
||||
#endif
|
||||
default:
|
||||
return (uintptr_t)0U;
|
||||
}
|
||||
@@ -257,6 +265,11 @@ static rs_status_t rs_sdio_send_app_command(rs_sdio_instance_t instance, uint16_
|
||||
|
||||
rs_status_t rs_sdio_probe(rs_sdio_instance_t instance, uint32_t *ip_id, uint32_t *version,
|
||||
uint32_t *capability) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || (ip_id == NULL) || (version == NULL) ||
|
||||
(capability == NULL) || (rs_sdio_read(instance, RS_SDIO_REG_IP_ID, ip_id) != RS_OK) ||
|
||||
(rs_sdio_read(instance, RS_SDIO_REG_IP_VERSION, version) != RS_OK) ||
|
||||
@@ -270,6 +283,11 @@ rs_status_t rs_sdio_probe(rs_sdio_instance_t instance, uint32_t *ip_id, uint32_t
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_reset(rs_sdio_instance_t instance, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
volatile uint32_t *status_reg;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance)) {
|
||||
@@ -294,6 +312,11 @@ rs_status_t rs_sdio_reset(rs_sdio_instance_t instance, rs_timeout_t timeout) {
|
||||
|
||||
rs_status_t rs_sdio_clock_set(rs_sdio_instance_t instance, uint32_t source_clock_hz,
|
||||
uint32_t target_clock_hz, rs_sdio_clock_t *clock) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_clock_t calculated;
|
||||
uint32_t value;
|
||||
uint32_t enabled;
|
||||
@@ -318,6 +341,11 @@ rs_status_t rs_sdio_clock_set(rs_sdio_instance_t instance, uint32_t source_clock
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_bus_width_set(rs_sdio_instance_t instance, rs_sdio_bus_width_t width) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t value;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || rs_sdio_busy(instance)) {
|
||||
@@ -338,6 +366,11 @@ rs_status_t rs_sdio_bus_width_set(rs_sdio_instance_t instance, rs_sdio_bus_width
|
||||
|
||||
rs_status_t rs_sdio_timeouts_set(rs_sdio_instance_t instance, uint32_t command_timeout,
|
||||
uint32_t data_timeout, uint32_t busy_timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || rs_sdio_busy(instance) || (command_timeout == 0U) ||
|
||||
(data_timeout == 0U) || (busy_timeout == 0U)) {
|
||||
return RS_EINVAL;
|
||||
@@ -351,6 +384,11 @@ rs_status_t rs_sdio_timeouts_set(rs_sdio_instance_t instance, uint32_t command_t
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_enable(rs_sdio_instance_t instance, bool enable) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t value;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) ||
|
||||
@@ -366,6 +404,11 @@ rs_status_t rs_sdio_enable(rs_sdio_instance_t instance, bool enable) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_configure(rs_sdio_instance_t instance, const rs_sdio_config_t *config) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_clock_t clock;
|
||||
rs_status_t status;
|
||||
|
||||
@@ -393,6 +436,11 @@ rs_status_t rs_sdio_configure(rs_sdio_instance_t instance, const rs_sdio_config_
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_status_get(rs_sdio_instance_t instance, rs_sdio_status_t *status) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t present;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || (status == NULL)) {
|
||||
@@ -421,6 +469,11 @@ rs_status_t rs_sdio_status_get(rs_sdio_instance_t instance, rs_sdio_status_t *st
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_command_start(rs_sdio_instance_t instance, const rs_sdio_command_t *command) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t cfg;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || (command == NULL) || (command->index > 63U) ||
|
||||
@@ -449,6 +502,11 @@ rs_status_t rs_sdio_command_start(rs_sdio_instance_t instance, const rs_sdio_com
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_response_get(rs_sdio_instance_t instance, rs_sdio_response_t *response) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || (response == NULL) ||
|
||||
(rs_sdio_read(instance, RS_SDIO_REG_RESP0, &response->words[0]) != RS_OK) ||
|
||||
(rs_sdio_read(instance, RS_SDIO_REG_RESP1, &response->words[1]) != RS_OK) ||
|
||||
@@ -462,6 +520,11 @@ rs_status_t rs_sdio_response_get(rs_sdio_instance_t instance, rs_sdio_response_t
|
||||
|
||||
rs_status_t rs_sdio_command_wait(rs_sdio_instance_t instance, rs_sdio_response_t *response,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || (response == NULL)) {
|
||||
@@ -485,6 +548,11 @@ rs_status_t rs_sdio_command_wait(rs_sdio_instance_t instance, rs_sdio_response_t
|
||||
|
||||
rs_status_t rs_sdio_command_execute(rs_sdio_instance_t instance, const rs_sdio_command_t *command,
|
||||
rs_sdio_response_t *response, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
|
||||
status = rs_sdio_command_start(instance, command);
|
||||
@@ -500,6 +568,11 @@ rs_status_t rs_sdio_command_execute(rs_sdio_instance_t instance, const rs_sdio_c
|
||||
|
||||
rs_status_t rs_sdio_data_configure(rs_sdio_instance_t instance,
|
||||
const rs_sdio_data_config_t *config) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t value;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || (config == NULL) || (config->block_size == 0U) ||
|
||||
@@ -532,6 +605,11 @@ rs_status_t rs_sdio_data_configure(rs_sdio_instance_t instance,
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_data_start(rs_sdio_instance_t instance) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || rs_sdio_busy(instance) ||
|
||||
(rs_sdio_irq_clear(instance, RS_SDIO_IRQ_DATA_DONE | RS_SDIO_IRQ_DATA_ERROR) != RS_OK) ||
|
||||
(rs_sdio_error_clear(instance, RS_SDIO_ERROR_DATA_CRC | RS_SDIO_ERROR_DATA_TIMEOUT |
|
||||
@@ -582,6 +660,11 @@ static rs_status_t rs_sdio_pio_store(rs_sdio_instance_t instance, const uint8_t
|
||||
|
||||
rs_status_t rs_sdio_pio_write(rs_sdio_instance_t instance, const void *buffer, size_t byte_count,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
const uint8_t *bytes = (const uint8_t *)buffer;
|
||||
rs_status_t status;
|
||||
size_t offset = 0U;
|
||||
@@ -612,6 +695,11 @@ rs_status_t rs_sdio_pio_write(rs_sdio_instance_t instance, const void *buffer, s
|
||||
|
||||
rs_status_t rs_sdio_pio_read(rs_sdio_instance_t instance, void *buffer, size_t byte_count,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint8_t *bytes = (uint8_t *)buffer;
|
||||
size_t offset = 0U;
|
||||
|
||||
@@ -645,6 +733,11 @@ rs_status_t rs_sdio_pio_read(rs_sdio_instance_t instance, void *buffer, size_t b
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_data_wait(rs_sdio_instance_t instance, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance)) {
|
||||
@@ -664,6 +757,11 @@ rs_status_t rs_sdio_data_wait(rs_sdio_instance_t instance, rs_timeout_t timeout)
|
||||
|
||||
rs_status_t rs_sdio_dma_setup(rs_sdio_instance_t instance, rs_sdio_descriptor_t *descriptors,
|
||||
uint16_t count, uint32_t total_bytes) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uintptr_t address;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || (total_bytes == 0U) ||
|
||||
@@ -686,6 +784,11 @@ rs_status_t rs_sdio_dma_setup(rs_sdio_instance_t instance, rs_sdio_descriptor_t
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_dma_start(rs_sdio_instance_t instance) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* DATA_START is the coordinated DMA/data-engine launch. Keep this
|
||||
* compatibility entry point as an alias so software cannot start a DMA
|
||||
@@ -695,6 +798,11 @@ rs_status_t rs_sdio_dma_start(rs_sdio_instance_t instance) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_dma_abort(rs_sdio_instance_t instance) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -702,6 +810,11 @@ rs_status_t rs_sdio_dma_abort(rs_sdio_instance_t instance) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_dma_status_get(rs_sdio_instance_t instance, rs_sdio_dma_status_t *status) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t dma_error;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) || (status == NULL) ||
|
||||
@@ -720,6 +833,11 @@ rs_status_t rs_sdio_dma_status_get(rs_sdio_instance_t instance, rs_sdio_dma_stat
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_dma_wait(rs_sdio_instance_t instance, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance)) {
|
||||
@@ -738,6 +856,11 @@ rs_status_t rs_sdio_dma_wait(rs_sdio_instance_t instance, rs_timeout_t timeout)
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_irq_enable(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || ((mask & ~RS_SDIO_IRQ_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -745,6 +868,11 @@ rs_status_t rs_sdio_irq_enable(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_irq_pending(rs_sdio_instance_t instance, uint32_t *mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || (mask == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -752,6 +880,11 @@ rs_status_t rs_sdio_irq_pending(rs_sdio_instance_t instance, uint32_t *mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_irq_clear(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || ((mask & ~RS_SDIO_IRQ_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -759,6 +892,11 @@ rs_status_t rs_sdio_irq_clear(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_irq_test(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || ((mask & ~RS_SDIO_IRQ_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -766,6 +904,11 @@ rs_status_t rs_sdio_irq_test(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_error_clear(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
if (!rs_sdio_instance_valid(instance) || ((mask & ~RS_SDIO_ERROR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
@@ -773,6 +916,11 @@ rs_status_t rs_sdio_error_clear(rs_sdio_instance_t instance, uint32_t mask) {
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_controller_selftest(rs_sdio_instance_t instance) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_status_t status;
|
||||
uint32_t ip_id;
|
||||
uint32_t version;
|
||||
@@ -916,7 +1064,9 @@ static rs_status_t rs_sd_memory_try_high_speed(rs_sdio_instance_t instance,
|
||||
return RS_EIO;
|
||||
}
|
||||
if (rs_sdio_clock_set(instance, source_clock_hz,
|
||||
(source_clock_hz >= 100000000U) ? 50000000U : 36000000U,
|
||||
rs_sdio_transfer_clock(source_clock_hz, (source_clock_hz >= 100000000U)
|
||||
? 50000000U
|
||||
: 36000000U),
|
||||
&clock) == RS_OK) {
|
||||
info->actual_clock_hz = clock.actual_hz;
|
||||
info->high_speed = true;
|
||||
@@ -928,6 +1078,11 @@ static rs_status_t rs_sd_memory_try_high_speed(rs_sdio_instance_t instance,
|
||||
|
||||
rs_status_t rs_sd_memory_initialize(rs_sdio_instance_t instance, uint32_t source_clock_hz,
|
||||
rs_sd_memory_info_t *info, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_response_t response;
|
||||
rs_sdio_clock_t clock;
|
||||
uint32_t payload;
|
||||
@@ -1008,7 +1163,9 @@ rs_status_t rs_sd_memory_initialize(rs_sdio_instance_t instance, uint32_t source
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
if ((rs_sdio_response_field(&response, 31U, 16U, &payload) != RS_OK) ||
|
||||
/* RESP retains the complete 48-bit frame: the R6 payload is [39:8],
|
||||
* so its upper sixteen RCA bits are [39:24], above the status/CRC. */
|
||||
if ((rs_sdio_response_field(&response, 39U, 24U, &payload) != RS_OK) ||
|
||||
(payload > UINT16_MAX)) {
|
||||
return RS_EFORMAT;
|
||||
}
|
||||
@@ -1046,7 +1203,8 @@ rs_status_t rs_sd_memory_initialize(rs_sdio_instance_t instance, uint32_t source
|
||||
info->bus_width_fallback = true;
|
||||
info->bus_width = RS_SDIO_BUS_WIDTH_1;
|
||||
}
|
||||
status = rs_sdio_clock_set(instance, source_clock_hz, 36000000U, &clock);
|
||||
status = rs_sdio_clock_set(instance, source_clock_hz,
|
||||
rs_sdio_transfer_clock(source_clock_hz, 36000000U), &clock);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
@@ -1150,12 +1308,22 @@ static rs_status_t rs_sd_memory_transfer(rs_sdio_instance_t instance,
|
||||
rs_status_t rs_sd_memory_read_blocks(rs_sdio_instance_t instance, const rs_sd_memory_info_t *info,
|
||||
uint32_t block, uint32_t count, void *buffer,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
return rs_sd_memory_transfer(instance, info, block, count, buffer, false, timeout);
|
||||
}
|
||||
|
||||
rs_status_t rs_sd_memory_write_blocks(rs_sdio_instance_t instance, const rs_sd_memory_info_t *info,
|
||||
uint32_t block, uint32_t count, const void *buffer,
|
||||
rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
return rs_sd_memory_transfer(instance, info, block, count, (void *)buffer, true, timeout);
|
||||
}
|
||||
|
||||
@@ -1175,6 +1343,11 @@ static rs_status_t rs_sdio_function_command(rs_sdio_instance_t instance, uint8_t
|
||||
|
||||
rs_status_t rs_sdio_function_cmd52_read(rs_sdio_instance_t instance, uint8_t function,
|
||||
uint32_t address, uint8_t *data, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_cmd52_t command = {
|
||||
.function = function,
|
||||
.address = address,
|
||||
@@ -1203,6 +1376,11 @@ rs_status_t rs_sdio_function_cmd52_read(rs_sdio_instance_t instance, uint8_t fun
|
||||
|
||||
rs_status_t rs_sdio_function_cmd52_write(rs_sdio_instance_t instance, uint8_t function,
|
||||
uint32_t address, uint8_t data, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
const rs_sdio_cmd52_t command = {
|
||||
.function = function,
|
||||
.address = address,
|
||||
@@ -1223,6 +1401,11 @@ rs_status_t rs_sdio_function_cmd52_write(rs_sdio_instance_t instance, uint8_t fu
|
||||
|
||||
rs_status_t rs_sdio_function_initialize(rs_sdio_instance_t instance, uint32_t source_clock_hz,
|
||||
rs_sdio_function_info_t *info, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_response_t response;
|
||||
rs_sdio_clock_t clock;
|
||||
uint32_t payload;
|
||||
@@ -1345,8 +1528,10 @@ rs_status_t rs_sdio_function_initialize(rs_sdio_instance_t instance, uint32_t so
|
||||
} else {
|
||||
info->high_speed_fallback = true;
|
||||
}
|
||||
status = rs_sdio_clock_set(instance, source_clock_hz,
|
||||
high_speed_enabled ? 24000000U : 25000000U, &clock);
|
||||
status = rs_sdio_clock_set(
|
||||
instance, source_clock_hz,
|
||||
rs_sdio_transfer_clock(source_clock_hz, high_speed_enabled ? 24000000U : 25000000U),
|
||||
&clock);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
@@ -1356,6 +1541,11 @@ rs_status_t rs_sdio_function_initialize(rs_sdio_instance_t instance, uint32_t so
|
||||
|
||||
rs_status_t rs_sdio_function_enable(rs_sdio_instance_t instance, rs_sdio_function_info_t *info,
|
||||
uint8_t function, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint8_t enable;
|
||||
uint8_t ready;
|
||||
uint32_t attempts;
|
||||
@@ -1394,6 +1584,11 @@ rs_status_t rs_sdio_function_cmd53_transfer(rs_sdio_instance_t instance, uint8_t
|
||||
uint32_t address, void *buffer, size_t byte_count,
|
||||
bool write, bool block_mode, bool fixed_address,
|
||||
uint16_t block_size, rs_timeout_t timeout) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
rs_sdio_cmd53_t command;
|
||||
rs_sdio_data_config_t data_config;
|
||||
rs_sdio_response_t response;
|
||||
@@ -1482,6 +1677,11 @@ rs_status_t rs_sdio_function_cmd53_transfer(rs_sdio_instance_t instance, uint8_t
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_function_irq_enable(rs_sdio_instance_t instance, bool enable) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t mask;
|
||||
|
||||
if (!rs_sdio_instance_valid(instance) ||
|
||||
@@ -1501,6 +1701,11 @@ rs_status_t rs_sdio_function_irq_enable(rs_sdio_instance_t instance, bool enable
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_function_irq_pending(rs_sdio_instance_t instance, bool *pending) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
uint32_t mask;
|
||||
|
||||
if ((pending == NULL) || (rs_sdio_irq_pending(instance, &mask) != RS_OK)) {
|
||||
@@ -1511,5 +1716,10 @@ rs_status_t rs_sdio_function_irq_pending(rs_sdio_instance_t instance, bool *pend
|
||||
}
|
||||
|
||||
rs_status_t rs_sdio_function_irq_ack(rs_sdio_instance_t instance) {
|
||||
#ifdef RS_SOC_TINY
|
||||
if (instance == RS_SDIO_INSTANCE_1) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
return rs_sdio_irq_clear(instance, RS_SDIO_IRQ_DAT1);
|
||||
}
|
||||
@@ -136,7 +136,9 @@ rs_status_t rs_sd_memory_parse_csd(const rs_sdio_response_t *response, rs_sd_mem
|
||||
return RS_EINVAL;
|
||||
}
|
||||
block_length = UINT32_C(1) << read_bl_len;
|
||||
capacity_bytes = ((uint64_t)c_size + UINT64_C(1)) * (UINT64_C(1) << (c_size_mult + 2U)) *
|
||||
/* C_SIZE_MULT is a three-bit CSD field: the shift is at most nine.
|
||||
* Keep the factor RV32-native; the enclosing product remains 64-bit. */
|
||||
capacity_bytes = ((uint64_t)c_size + UINT64_C(1)) * (UINT32_C(1) << (c_size_mult + 2U)) *
|
||||
(uint64_t)block_length;
|
||||
capacity_blocks = capacity_bytes / (uint64_t)RS_SD_MEMORY_BLOCK_SIZE;
|
||||
info->card_type = RS_SD_MEMORY_SDSC;
|
||||
|
||||
@@ -84,6 +84,12 @@ static rs_status_t rs_uart_flow_gpio_configure(const rs_uart_config_t *config) {
|
||||
};
|
||||
rs_status_t status = RS_OK;
|
||||
|
||||
#ifdef RS_SOC_TINY
|
||||
status = rs_gpio_configure(8U, &pin_config);
|
||||
if (status == RS_OK) {
|
||||
status = rs_gpio_configure(9U, &pin_config);
|
||||
}
|
||||
#endif
|
||||
if (config->auto_cts_enable) {
|
||||
status = rs_gpio_configure(RS_UART_CTS_GPIO, &pin_config);
|
||||
}
|
||||
@@ -106,6 +112,11 @@ rs_status_t rs_uart_configure(const rs_uart_config_t *config, rs_timeout_t timeo
|
||||
return RS_EINVAL;
|
||||
}
|
||||
|
||||
#ifdef RS_SOC_TINY
|
||||
if (config->auto_cts_enable || config->auto_rts_enable) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
RS_UART_CTRL = 0U;
|
||||
while (((RS_UART_STATUS & (RS_UART_STATUS_TX_BUSY | RS_UART_STATUS_RX_BUSY)) != 0U) &&
|
||||
(timeout != 0U)) {
|
||||
|
||||
@@ -419,7 +419,11 @@ rs_status_t rs_ws2812_dma_service(uint64_t now) {
|
||||
return rs_ws2812_dma_finish();
|
||||
}
|
||||
if ((transmitter_flags & RS_WS2812_STATUS_BUSY) == 0U) {
|
||||
return rs_ws2812_dma_fail(RS_EIO);
|
||||
/* Completion may occur between the interrupt and status reads, and
|
||||
* sticky DONE can lag the core's idle transition. Observe terminal
|
||||
* events on the next bounded service call; never refill an idle core.
|
||||
* Errors, aborts and the deadline remain checked on every call. */
|
||||
return RS_OK;
|
||||
}
|
||||
if (rs_ws2812_transfer.remaining == 0U) {
|
||||
rs_ws2812_write_register(RS_WS2812_INTR_STATE_OFFSET, RS_WS2812_INTR_FIFO_LOW);
|
||||
|
||||
Vendored
+1
-1
@@ -158,7 +158,7 @@
|
||||
"cluster_common": {"url": "https://github.com/retroSoC/common.git", "revision": "964a54d70cb78e394ba9a25c05f2aa2b02941fb7", "destination": "rtl/managed/clusterip/common", "license": "NOASSERTION"},
|
||||
"cluster_crc": {"url": "https://github.com/retroSoC/crc.git", "revision": "8c1a5664c4d23d005c1afad432372a13ca967cc8", "destination": "rtl/managed/clusterip/crc", "license": "MulanPSL-2.0"},
|
||||
"cluster_ps2": {"url": "https://github.com/retroSoC/ps2.git", "revision": "2097a0d41b07573ff0453d65ba9a1670b3df7b9c", "destination": "rtl/managed/clusterip/ps2", "license": "MulanPSL-2.0"},
|
||||
"cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "79ae32f725e848a1e7f6134847b3fb032ed64006", "destination": "rtl/managed/clusterip/pwm", "license": "MulanPSL-2.0"},
|
||||
"cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "38efaf5e20f084a00148920087c60cadab61839b", "destination": "rtl/managed/clusterip/pwm", "license": "MulanPSL-2.0"},
|
||||
"cluster_rng": {"url": "https://github.com/retroSoC/rng.git", "revision": "36f3e0774d8f3c4b597d3db8a96ca3992532b61e", "destination": "rtl/managed/clusterip/rng", "license": "MulanPSL-2.0"},
|
||||
"cluster_rtc": {"url": "https://github.com/retroSoC/rtc.git", "revision": "32548c5cbcdf39e09d0880fb611f9dd47940ea88", "destination": "rtl/managed/clusterip/rtc", "license": "NOASSERTION"},
|
||||
"cluster_wdg": {"url": "https://github.com/retroSoC/wdg.git", "revision": "f5d39fa246054d678d34195824d943367dfcce44", "destination": "rtl/managed/clusterip/wdg", "license": "MulanPSL-2.0"}
|
||||
|
||||
+4
-2
@@ -3,8 +3,10 @@
|
||||
## Supported Profiles
|
||||
|
||||
Tiny's [2026-10-07 specification default](ip/tiny-soc.md#ics55-default-platform-and-final-timing-gate-2026-10-07)
|
||||
is ICS55/PLL with SAFE24 boot. The executable default keeps the PLL parked off;
|
||||
PLL-driven SYS and physical qualification remain later work. The table
|
||||
is ICS55/PLL with SAFE24 boot. The PLL starts parked off; the
|
||||
[R2-P7 implementation](ip/tiny-soc-r2-clock-reset.md) adds explicit software
|
||||
transitions with separate functional evidence. Physical qualification remains
|
||||
pending. The table
|
||||
describes executable profiles, not qualified operating rates.
|
||||
For Tiny and its SPI/PIO-lite/PPALite extensions only, pre-final post-synthesis
|
||||
timing closure is observational. Retain STA attempts/failures and all required
|
||||
|
||||
@@ -105,6 +105,15 @@ change.
|
||||
in `[23:0]`. `TKEEP` and `TSTRB` are `4'hF`. I2S RX does not assert `TLAST`.
|
||||
DMA asserts `TLAST` on the final programmed TX word.
|
||||
|
||||
The P6 integration regression uses alternating sample least-significant bits
|
||||
in both 16- and 24-bit pin-level loopback. It exposed a receiver defect that
|
||||
combined the preceding sample's last bit with the next sample. The corrected
|
||||
receiver appends the bit sampled at the LRCK transition to the preceding
|
||||
sample's shifted bits and registers completion after that value is available.
|
||||
This preserves the host register/stream ABI and does not add slave mode.
|
||||
The register frontend uses PWRITE for transfer direction. In particular, a
|
||||
write with zero byte strobes cannot be reinterpreted as a side-effecting RX read.
|
||||
|
||||
## HAL Sequence
|
||||
|
||||
Mini applications should use `rs_i2s_configure()`, `rs_i2s_enable()`, and either
|
||||
|
||||
@@ -180,3 +180,47 @@ The standalone IP does not allocate memory, perform cache maintenance,
|
||||
implement an IOMMU/firewall, or provide a hosted/runtime C API. The SoC
|
||||
integration only supplies the two native AXI/APB/IRQ/pad paths; the SDK driver
|
||||
is maintained by a separate workstream.
|
||||
|
||||
## Tiny SAFE24 integration
|
||||
|
||||
Tiny R2-P6 connects instance 0 to external AXI owner 2, its independent APB
|
||||
branch and IRQ10, and GPIO0..5. Instance 1 remains absent and its public SDK
|
||||
operations return `RS_ENOTSUP` before MMIO. These bindings do not replace the
|
||||
Mini mappings above. The 24 MHz input permits at most 12 MHz SDCLK; enumeration
|
||||
still starts at 400 kHz and the SDK caps later protocol requests at input/2.
|
||||
|
||||
R6 is retained as the complete 48-bit frame in RESP. RCA therefore occupies
|
||||
bits 39:24, above the payload status and CRC/end bits. The shared initialization
|
||||
helper uses this field rather than bits 31:16; no register or public API changes.
|
||||
|
||||
The command sender enables its first output bit at its scheduled launch. A
|
||||
command admitted on an already running SDCLK rising edge must not expose an
|
||||
extra start bit. Directed pad sampling covers repeated command admission at
|
||||
both half-cycle phases in Icarus and Verilator. The card model collects the
|
||||
complete 48-bit frame after its start bit, including the pulled-high end bit
|
||||
after host output release; host output-enable is not the frame length oracle.
|
||||
|
||||
The transmit wait indication also covers the last bit of a word when its
|
||||
successor is unavailable. The core pauses SDCLK before the next word's launch,
|
||||
while retaining the current driven bit and draining the high half-cycle. This
|
||||
prevents an idle bit from becoming the next word's MSB under memory backpressure.
|
||||
A 1024-byte four-lane DMA case inserts 24 system cycles between read beats and
|
||||
checks every card byte, CRC status and descriptor retirement through real
|
||||
three-state lines. Inactive lanes stay pulled high in the card's token/tail checks.
|
||||
|
||||
Card-to-memory DMA retains descriptor ownership across every AXI burst, rather
|
||||
than publishing DONE after the first 64 bytes. Receive backpressure stops the
|
||||
next SDCLK launch as soon as a complete word is held; a registered stop loses
|
||||
the next card bit. The roundtrip fixture delays descriptor fetch as well as
|
||||
payload supply, checks all 1024 received bytes and successful final writeback.
|
||||
Its card emits all sixteen CRC bits in order; earlier manual-model tests did
|
||||
not reject the skipped CRC bit. These fixes preserve the native one-read/one-write
|
||||
capacity, descriptor layout, register ABI and interrupt/error lifecycle.
|
||||
|
||||
The existing verification card keeps its manually scheduled standalone mode.
|
||||
Tiny selects its optional SDHC enumeration responses with 1024 512-byte blocks
|
||||
and default-speed-only capability. Its board fixture checks the observed wire
|
||||
command, direction, width and length, then calls the existing data-stimulus API
|
||||
at DATA_START. All payload and response bits cross the real pads. This checks
|
||||
the repository controller/SDK contract; it does not qualify arbitrary card
|
||||
response timing, SD protocol compliance, a physical card or an electrical rate.
|
||||
@@ -0,0 +1,385 @@
|
||||
# Tiny R2-P7 clock/reset implementation and evidence
|
||||
|
||||
This phase starts at `43a3c8d453b6d41df3536719ebc6d1f4521bc7cd`, against frozen
|
||||
specification blob `7e19de49d49efaafacccfa85671e314d53dd15a4`. Implementation
|
||||
is authorized; phase acceptance still requires review of the completed gates.
|
||||
No P8 implementation, commit, push, or physical frequency qualification follows.
|
||||
|
||||
## Product and ownership
|
||||
|
||||
`configs/ci/ics55-tiny.mk` remains the default: TINY, ICS55, PLL present,
|
||||
SAFE24 boot. The single RCU-owned PLL starts off. Software may request the
|
||||
functional PLL192/PLL240 profiles after draining clients. These are digital
|
||||
simulation capabilities, not characterized silicon operating points.
|
||||
`configs/ci/ihp130-tiny.mk` remains the explicit no-PLL 24 MHz compatibility
|
||||
profile. `ihp130-tiny-xin48.mk` and `ihp130-tiny-xin96.mk` add declared external
|
||||
input variants, both normalizing the boot/control reference to 24 MHz.
|
||||
|
||||
CPU, all 32 main SRAM macros, bank frontends, fabric and SDIO share active SYS.
|
||||
Only the CPU leaf stops for WFI. XPI data/control use MEM. DMA, shared serial
|
||||
and security IP and the six private Crypto macros use PCLK. Crypto capacity
|
||||
and erasure policy are unchanged. AON owns RCU, CLINT and RTC/WDG functional
|
||||
timekeeping; AUDIO is optional at boot. The historical ASIC wrapper and frozen
|
||||
QFN64/pad contract are retained under the existing P6 qualification boundary.
|
||||
|
||||
Tiny owns the clock backend, admission holders, APB/AXI crossings, peripheral
|
||||
lifecycle controller, CPU gate, CLKOUT and SYSCTRL ABI. Common clock mux,
|
||||
divider, reset barrier, synchronizers and CDC primitives are reused without
|
||||
editing managed sources. New optional shared-IP lifecycle outputs preserve
|
||||
Mini defaults; the debug wrapper's separate system reset is opt-in. Managed
|
||||
PWM/CRC lifecycle mirrors observe successful writes at their existing ABI.
|
||||
The already approved PWM lock remains
|
||||
`38efaf5e20f084a00148920087c60cadab61839b`.
|
||||
|
||||
RCU occupies `SYSCTRL+0x100..0x15c`, IRQ31. Handwritten SVH/C definitions
|
||||
have a 24-register parity test. `rcu.h` supplies bounded Tiny-specific profile,
|
||||
snapshot, gate, local/system reset, cause/fault and CLKOUT operations. Invalid,
|
||||
unsupported, busy, timeout and hardware-error results are distinct. No new
|
||||
MISRA Required-rule deviation is introduced. Future targets 14–17 remain
|
||||
absent; no SPI, PIO-lite, DVP, PPALite or PSRAM rollout is included.
|
||||
|
||||
## Lifecycle and failure boundaries
|
||||
|
||||
Clock requests block new admissions after command acceptance, drain accepted
|
||||
CPU/local/AXI/APB traffic, park on REF24, configure conservative divisors,
|
||||
qualify the source, then commit rate snapshots before unblocking. Stalled
|
||||
addresses already accepted into admission holders retain VALID/payload.
|
||||
Unaccepted requests may remain pending and resume after switching. An
|
||||
insufficient transition budget fails before changing the committed profile.
|
||||
PLL lock timeout publishes the complete SAFE24 fallback. PLL stuck-low/high
|
||||
requires a system/CDC reset before forced mux recovery; XIN loss needs source
|
||||
restoration and external reset.
|
||||
|
||||
Local resets hold for five actual leaf edges and release through five-edge
|
||||
synchronizers and bus barriers. I2S additionally requires actual AUDIO-side
|
||||
reset readiness; missing AUDIO cannot manufacture RESET_DONE. Gate changes
|
||||
wait for idle; CPU-only WFI permission does not pause unrelated DMA. Current
|
||||
non-CPU lifecycle commands conservatively drain all central-DMA work before
|
||||
changing the selected targets. This can reject a request while an unrelated
|
||||
DMA stream remains active; it does not stop that stream by gating its clock.
|
||||
Warm reset retains cause/fault/debug state, aborts interrupted debug commands,
|
||||
restores SAFE24, resets functional RTC/WDG state and preserves main SRAM data.
|
||||
|
||||
The 2026-10-14 P7 review correction keeps the XPI fabric target and AXI bridge
|
||||
source endpoint on SYS reset while the XPI/MEM endpoint uses its MEM leaf reset.
|
||||
The later response-conservation correction uses source-owned response holders:
|
||||
already presented B/R responses remain stable and retire once, while missing
|
||||
read beats receive DECERR and aborted writes drain W before B. Admission allows
|
||||
one outstanding request in each direction. Payload source reset uses the
|
||||
five-edge link barrier; the response holders reset only with the source.
|
||||
An unfinished warm clear holds isolation until destination reset so that late
|
||||
responses cannot enter another transaction. Production DMA/XPI clear inputs
|
||||
remain tied low. A failed drain does not trigger an invented autonomous AXI
|
||||
timeout or peripheral reset. The focused tests now cover these protocol
|
||||
boundaries in both simulators; earlier 36-case results did not establish them.
|
||||
|
||||
Source-only reset has a separate production precondition. The DMA source
|
||||
may reset locally only after its engine and accepted admission/fabric work
|
||||
drain. The controller blocks new admissions, waits at least 16 REF24 cycles
|
||||
for the synchronized observations, and leaves the source running on drain
|
||||
timeout. XPI has no independent SYS-source reset: the common system reset
|
||||
also asserts its MEM endpoint reset. The standalone AXI bridge does not
|
||||
cancel a live remote slave's work on an arbitrary source-only reset and must
|
||||
not be reused with that assumption.
|
||||
|
||||
The focused `tiny_p7_source_reset_tb` extracts the production controller,
|
||||
admission, bridge, synchronizers and reset bindings into its fixture and uses
|
||||
the real DMA AXI master. It checks stalled addresses, partial writes, late
|
||||
responses, held read responses, timeout, recovery and common reset at all five
|
||||
declared domain ratios. A scoreboard independent of local reset detects the
|
||||
deliberately broken-drain negative case. Unrelated clients and the completion
|
||||
mailbox are idle; the target is a behavioral slave. This supplies executable
|
||||
integration-contract coverage, not a general arbitrary-reset proof or physical
|
||||
qualification. The new evidence is under `06-00.../meta/tiny-r2-p7-source-reset/`
|
||||
as detailed in the verification ledger; production RTL and backend inputs are
|
||||
unchanged by this follow-up.
|
||||
|
||||
The follow-up validation commands are:
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
p7_reset_evidence=build/ics55-tiny-2026-10-14-06-00-ff4b5cef6eb5/meta/tiny-r2-p7-source-reset
|
||||
PYTHONDONTWRITEBYTECODE=1 python3 scripts/run_flow.py --tool pytest \
|
||||
--log "$p7_reset_evidence/directed.log" \
|
||||
--result "$p7_reset_evidence/result-directed.json" -- \
|
||||
python3 -m pytest -q tests/test_tiny_r2_p7.py \
|
||||
--basetemp="$p7_reset_evidence/directed-tests"
|
||||
make --silent CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 \
|
||||
rtl-format-check rtl-style-check-all check-clock-reset-domains
|
||||
ruff check .
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
|
||||
git diff --check
|
||||
```
|
||||
|
||||
These paths identify the retained execution, not an instruction to overwrite
|
||||
it: use a fresh evidence directory for any retry. `source.json` binds the new
|
||||
tests and `verification-update.json` compares them to the original `06-00`
|
||||
snapshot. Only the two verification files differ; all 1728 other technical
|
||||
inputs and tool identities match. No firmware, full-SoC, synthesis, netlist or
|
||||
STA flow is repeated for this verification-only correction. The earlier
|
||||
full-suite Pytest and full-Icarus limitations below remain explicit.
|
||||
|
||||
The first post-fix physical smoke campaign below is historical. Each PDK has
|
||||
its own profile/configuration digest. These results precede the final response
|
||||
holders; current source evidence is recorded in the verification ledger.
|
||||
|
||||
| PDK | Variant | Synthesis | Netlist boot | STA |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| ICS55 | `build/ics55-tiny-2026-10-14-01-20-ff4b5cef6eb5` | PASS, 2122.685 s | PASS, 1656.024 s, `SIM_TEST_PASS Tiny netlist boot` | PASS observation; WNS max/min `-144.40/-0.31 ns`, TNS max/min `-4859636.50/-45.04` |
|
||||
| IHP130 | `build/ihp130-tiny-2026-10-14-01-20-8232fa11e7f3` | PASS, 1925.337 s | PASS, 586.861 s, `SIM_TEST_PASS Tiny netlist boot` | PASS observation; WNS max/min `-257.81/-0.47 ns`, TNS max/min `-9807803.00/-100.68` |
|
||||
|
||||
The current frozen-source `06-00` campaign supersedes the historical table for
|
||||
post-fix qualification:
|
||||
|
||||
| PDK | Variant | Synthesis | Netlist boot | STA |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| ICS55 | `build/ics55-tiny-2026-10-14-06-00-ff4b5cef6eb5` | PASS, 2108.388 s | PASS, 1655.980 s, `SIM_TEST_PASS Tiny netlist boot` | PASS observation; WNS max/min `-152.03/-0.31 ns`, TNS max/min `-5622052.50/-44.14` |
|
||||
| IHP130 | `build/ihp130-tiny-2026-10-14-06-00-8232fa11e7f3` | PASS, 1934.515 s | PASS, 578.869 s, `SIM_TEST_PASS Tiny netlist boot` | PASS observation; WNS max/min `-253.43/-0.49 ns`, TNS max/min `-10035324.00/-153.37` |
|
||||
|
||||
The STA markers explicitly identify SAFE24/observational analysis; neither
|
||||
variant qualifies an active PLL, routed implementation, PVT corner or product
|
||||
operating point. The `04-00` source candidate was later rejected by the
|
||||
response-conservation tests. The `06-00` source-bound post-fix campaign is the
|
||||
current qualification run and all requested synthesis, netlist and STA gates
|
||||
pass. Its measured results are recorded in the ledger. Full firmware Icarus
|
||||
remains deferred to the final Tiny phase.
|
||||
|
||||
Source/divisor/enable for CLKOUT are committed together, cross to the selected
|
||||
source, and finish the current output high pulse before disabling. GPIO28 ALT0
|
||||
and GPIO23 ALT1 consume the same generator. Illegal/live changes return
|
||||
PSLVERR and leave the previous configuration unchanged.
|
||||
|
||||
## Validation sequence and commands
|
||||
|
||||
Activate the locked environment before these commands:
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
|
||||
python3 -m pytest -q tests/test_tiny_r2_p7.py tests/test_tiny.py tests/test_tiny_r2_p4.py tests/test_tiny_r2_p5.py
|
||||
make sw-format-check sw-policy-check sw-host-test
|
||||
make rtl-format-check rtl-style-check-all rtl-readiness-check check-clock-reset-domains
|
||||
ruff check .
|
||||
python3 scripts/dependency_lock.py --lock dependencies/dependencies.lock.json
|
||||
python3 -m pytest -q
|
||||
git diff --check
|
||||
```
|
||||
|
||||
The direct long-flow commands use the selected regression's targets with
|
||||
larger explicit wall-time budgets. The identical Tiny nightly matrix does not
|
||||
need a second execution. Every row below runs once per PDK, with
|
||||
`CONFIG=configs/ci/<pdk>-tiny.mk SOC=TINY PDK=<PDK> APP=ci_smoke HAVE_SVA=YES`:
|
||||
|
||||
| Purpose | BUILD_TIMESTAMP | Remaining Make arguments |
|
||||
| --- | --- | --- |
|
||||
| P7 Verilator | `2026-10-13-17-05` | `TINY_P7_ACCEPTANCE=YES SIMU=VERILATOR SOC_SIM_TIME=3600 TINY_SIM_TIMEOUT=6000000 TINY_SIM_ARGS=+p7_monitor sim` |
|
||||
| P7 Icarus | `2026-10-13-17-06` | `TINY_P7_ACCEPTANCE=YES SIMU=IVERILOG TINY_SIM_TIMEOUT=6000000 TINY_SIM_ARGS=+p7_monitor 'TINY_RUN=timeout --foreground 14400s $(VVP) $(SIM_BUILD_ROOT)/simv' sim` |
|
||||
| Physical macro synthesis | `2026-10-13-17-15` | `HAVE_SVA=NO SYNTH=YOSYS YOSYS_TIMEOUT=10800 synth` |
|
||||
| Full firmware/JTAG, P7 watchdog-cause adaptation, Verilator | `2026-10-13-18-25` | `SIMU=VERILATOR SOC_SIM_TIME=7200 TINY_SIM_TIMEOUT=30000000 TINY_SIM_ARGS=+tiny_jtag_smoke sim` |
|
||||
| Full firmware/JTAG, P7 watchdog-cause adaptation, Icarus | `2026-10-13-18-26` | `SIMU=IVERILOG TINY_SIM_TIMEOUT=30000000 TINY_SIM_ARGS=+tiny_jtag_smoke 'TINY_RUN=timeout --foreground 36000s $(VVP) $(SIM_BUILD_ROOT)/simv' sim` |
|
||||
| Netlist boot, after synthesis | `2026-10-13-17-15` | `HAVE_SVA=NO SIMU=IVERILOG netsim-boot` |
|
||||
| Observational core STA, after synthesis | `2026-10-13-17-15` | `HAVE_SVA=NO 'STA_BUILD_ROOT=$(VARIANT_ROOT)/sta/opensta-p7-v3' STA=OPENSTA sta` |
|
||||
|
||||
Warning/metric collection uses each corresponding variant. New EDA signatures
|
||||
remain observations; no warning baseline or metric policy is edited. Compiler
|
||||
warning policy and Tiny functional verdicts remain required.
|
||||
|
||||
After correcting the external-input POR reference, the actual-SoC P7 image is
|
||||
also run with `CONFIG=configs/ci/ihp130-tiny-xin48.mk` and
|
||||
`CONFIG=configs/ci/ihp130-tiny-xin96.mk`, `SOC=TINY PDK=IHP130 APP=ci_smoke
|
||||
TINY_P7_ACCEPTANCE=YES HAVE_SVA=YES TINY_SIM_ARGS=+p7_monitor
|
||||
TINY_SIM_TIMEOUT=24000000`. Verilator uses timestamp `2026-10-13-18-40`,
|
||||
`SIMU=VERILATOR SOC_SIM_TIME=7200 sim`; final Icarus uses `2026-10-13-20-05`,
|
||||
`SIMU=IVERILOG 'TINY_RUN=timeout --foreground 21600s $(VVP) $(SIM_BUILD_ROOT)/simv' sim`.
|
||||
The larger cycle budget counts raw XIN edges, not SYS/REF24 cycles. These are
|
||||
additional source configurations, not repetitions of a single benchmark.
|
||||
|
||||
The initial XIN48/96 Icarus attempts (`18-41`) produced a premature terminal
|
||||
write but failed the independent P7 lifecycle coverage checks, so they remain
|
||||
FAIL. A short actual-SoC comparison reproduced unknown RCU cause/fault state
|
||||
with the old reset declaration initialized low at time zero. REF24 has no edges
|
||||
while its input divider is reset; an explicit external RESET_N assertion at
|
||||
1 ns, before the first XIN edge, initializes the asynchronous state correctly.
|
||||
Both old-stimulus negative probes fail and both asserted-reset probes pass,
|
||||
under `20-05.../meta/cold-reset/`. The testbench now checks exact known cold
|
||||
state and rejects an unknown terminal pass/code. This is a verification-stimulus
|
||||
repair, with no forced DUT state or synthesizable RTL change. The Verilator
|
||||
source cases and existing 24 MHz runs are retained separately; only the two
|
||||
failed Icarus source cases are replayed, with the same firmware hashes.
|
||||
|
||||
## Workloads and provenance
|
||||
|
||||
The separate `TINY_P7_ACCEPTANCE=YES` configuration key selects the short P7
|
||||
firmware without replacing the original acceptance application. It exercises
|
||||
all supported profile selections for the chosen backend, 128-word SRAM
|
||||
retention, atomic rate readback, PWM rate readback, CLINT monotonicity and an
|
||||
independent PCLK timer measurement over at least 200 CLINT ticks. The timer
|
||||
check allows bounded APB read skew but rejects /2 or /4 domain mistakes.
|
||||
It gates/ungates/resets timer0, copies 1024 words through DMA while CPU WFI is
|
||||
armed, wakes on CLINT, and requests software reset with a retained `.noinit`
|
||||
sentinel. The observer must see actual CPU gated cycles, DMA responses during
|
||||
that interval, supported profile commits and exactly one software reset.
|
||||
|
||||
Tiny PASS requires command success, TEST_STATUS/SIM_TEST_PASS, and absence of
|
||||
FAILED/FATAL/assertion failed/%Error/SIM_TEST_FAIL/SIM_TEST_TIMEOUT. P7 also
|
||||
requires `P7_LIFECYCLE_PASS`. The old full firmware additionally retains its
|
||||
P6 peripheral/wire/AXI records and JTAG checks. UART output is diagnostic only.
|
||||
|
||||
The completed P7 firmware results below match between Verilator and Icarus.
|
||||
All eight images use the same retained binary. Cycles count raw XIN edges and
|
||||
must not be compared as CPU cycles across different XIN configurations.
|
||||
|
||||
| Source/profile | Terminal cycles in each simulator | Actual gated SYS cycles | DMA responses while gated |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| ICS55 XIN24, PLL192/240/SAFE24 | 3,525,681 | 71,614 | 64 |
|
||||
| IHP130 XIN24, external/SAFE24 | 3,521,913 | 71,623 | 64 |
|
||||
| IHP130 XIN48, external/SAFE24 | 7,038,466 | 71,635 | 64 |
|
||||
| IHP130 XIN96, external/SAFE24 | 14,071,429 | 71,615 | 64 |
|
||||
|
||||
Each run also records exactly one software reset and verifies SRAM retention.
|
||||
|
||||
The source record is
|
||||
`build/ics55-tiny-2026-10-13-17-05-f3e42d54c18b/meta/tiny-r2-p7/source.json`.
|
||||
It retains repository state, the exact specification, locked tool identities,
|
||||
source hashes, patch and a source archive, including untracked implementation
|
||||
files. `scripts/tiny_r2_p7.py verify-source` checks the retained source set.
|
||||
The Make formatter subsequently changed only the terminal newline in eight
|
||||
Make/configuration files. `make-format-equivalence.json` checks every changed
|
||||
file byte-for-byte except that final newline; RTL, firmware, tests and tool
|
||||
scripts are identical. `formatted/source.json` retains the final formatting
|
||||
snapshot separately, without overwriting the source consumed by running jobs.
|
||||
Subsequent validation corrections update the commercial six-domain SAFE24
|
||||
adapter/test and connect the top-level POR counter to normalized REF24. The
|
||||
external-source fixture now requires five actual REF24 edges at 24/48/96 MHz
|
||||
and compares old/new reset-tree outputs at 24 MHz in both simulators (seven
|
||||
checks pass). For every retained long-flow configuration, XIN is 24 MHz and
|
||||
the backend directly wires XIN to REF24, so that one port reconnection is an
|
||||
exact alias substitution. The original source remains the provenance of those
|
||||
runs; the documented equivalence and focused higher-input-rate tests cover
|
||||
the correction without repeating default-profile simulations.
|
||||
Build variants retain effective configuration, generated filelists, firmware
|
||||
ELF/bin/hex/map, simulator binaries, command logs and structured terminal
|
||||
results. Match binaries by SHA-256 across simulators, and retain flags and
|
||||
plusargs with results; do not mix these images with compiler/layout experiments.
|
||||
|
||||
The four P7 binaries (both PDKs and both simulators) have SHA-256
|
||||
`0a536fbbae9832de7ba5a82f7688a147b96a57435a66249b5e8de18bad1c01c5`.
|
||||
The initial full ICS55 firmware matched between simulators at
|
||||
`e4cb5965b9b9ddb1135a0a672327113ed8b378ace56e1a4ee771374309c18a15`;
|
||||
the initial full IHP130 firmware matched at
|
||||
`048bd15221fcbd25986abaa2d973e74d101f3a8ac8f328a6169442ba8acabacb`.
|
||||
The corrected watchdog-acceptance full images match between simulators at
|
||||
ICS55 `69b8582099c8735e81014b9c3f5685d9212a58c18b820a8c9a611a6f64a2f6c4`
|
||||
and IHP130 `efc0b403f32669332e942cb63ee9bb2b035a6e462e68e0a5a1524dea01c6c298`.
|
||||
|
||||
P7 has its own structural netlist audit. It requires 32 main and six private
|
||||
Crypto physical SRAM macros, main-SRAM/CPU SYS equality, the CPU-only gate,
|
||||
Crypto PCLK binding and exactly one real ICS55 PLL driving the SYS mux.
|
||||
The audit binds configuration digest, netlist/JSON and audit-script hashes.
|
||||
The strict historical P1 parked-PLL/direct-SYS audit is unchanged.
|
||||
|
||||
Core STA analyzes SAFE24 boot, with explicit mux/PLL case analysis. Retain
|
||||
clocks, setup/hold, coverage, recovery/removal and constraint-violation reports.
|
||||
It excludes pad/board/routed/PVT and active-PLL qualification. Negative slack
|
||||
is observational before the final combined product campaign, not evidence of
|
||||
qualification and not permission to omit synthesis or netlist functionality.
|
||||
The commercial adapter mirrors the same six-domain SAFE24 inventory and
|
||||
requires explicit mux/PLL case selections; its host tests pass. Internal /2,
|
||||
/4 and CLKOUT-source clocks supplement the six root domains. Settled mux gate
|
||||
state is constrained because a select request alone does not propagate through
|
||||
the mux's sequential handshake in static analysis. The initial and second STA
|
||||
attempts remain under `sta/opensta` and `sta/opensta-p7-v2`; the final observation
|
||||
is under `sta/opensta-p7-v3`. No licensed
|
||||
commercial execution, active-PLL SDC, routed extraction, board IO or package
|
||||
qualification is supplied by those host tests.
|
||||
|
||||
Historical `2026-10-13-17-15` SAFE24 observations, in ns, are ICS55 setup/hold WNS −147.48/−0.31,
|
||||
TNS −4758121.50/−45.30; IHP130 WNS −275.45/−0.50,
|
||||
TNS −9958118.00/−102.84. The worst setup cone begins at the fabric reset leaf,
|
||||
whose direct fanout is over 10,000; no reset false path was added to hide it.
|
||||
The v3 coverage reports retain excluded pad IO budgets, 42 unclocked ICS55 PLL
|
||||
monitor/mux pins while that source is off, and 5 ICS55 / 6 IHP130 control pins
|
||||
with multiple clock tags. These are explicit limits of this settled SAFE24
|
||||
observation, not complete-mode timing coverage or signoff. These values and
|
||||
coverage counts belong to that historical netlist; the current `06-00` WNS/TNS
|
||||
are in the table above, with their own retained coverage reports.
|
||||
|
||||
The single full Pytest attempt records 1696 passed, 6 failed, 60 setup errors
|
||||
and one optional `pypdf` skip. Two failures were the commercial domain policy;
|
||||
60 setup errors and one failure shared the missing `RS_EBUSY=-8` SDK return
|
||||
entry in the publication's source-checked table. Both are corrected; the
|
||||
commercial/STA tests pass and the publication subset records 110 passed/one
|
||||
skip. The remaining three Icarus failures used a test module collected before
|
||||
the external-reset fixture acquired its `tiny_reset_tree` dependency; the
|
||||
updated test command explicitly supplies it and all seven external-source/reset
|
||||
checks pass. Keep that original full-suite result and these focused reruns;
|
||||
do not report an unexecuted clean full-suite pass. Only the shared return-code
|
||||
table changes in the publication; no source identity, PDF, edition or release
|
||||
qualification is advanced.
|
||||
|
||||
## Interrupted and historical attempts
|
||||
|
||||
Earlier October 13 build directories are development snapshots. In particular,
|
||||
the `15-45-f3e42d54c18b` Verilator attempt passed at 3,281,032 cycles and observed
|
||||
71,612 gated cycles, 64 DMA responses while gated and one warm reset. Later
|
||||
corrections mean that result is not final-source acceptance. Earlier synthesis
|
||||
attempts failed obsolete P1 checks; a temporary weakened P1 audit is invalid
|
||||
evidence and was restored. No current physical result may be inferred from it.
|
||||
|
||||
The first final-campaign synthesis attempt (`17-07`, SVA enabled) failed during
|
||||
Slang elaboration on unsupported temporal assertion syntax. It did not run
|
||||
mapping. The `17-15` retry uses the existing regression's `HAVE_SVA=NO` synthesis
|
||||
configuration; behavioral/SVA verification remains separate and unchanged.
|
||||
|
||||
The `17-08` complete Verilator runs passed all first-boot peripherals, then
|
||||
incorrectly repeated the firmware after watchdog reset and failed recovery
|
||||
code 26 on the second pass. The old firmware inferred warm boot from the
|
||||
watchdog's functional `reset_count`; P7 intentionally resets that state. The
|
||||
corrected firmware checks retained RCU cause bit 2, verifies that watchdog
|
||||
functional state was cleared and SAFE24 restored, and requires an SRAM `.noinit`
|
||||
cookie set only after all first-boot tests. This preserves the complete test
|
||||
sequence and watchdog acceptance rather than restoring obsolete retention.
|
||||
The corresponding `17-09` Icarus runs were cancelled as obsolete; controller
|
||||
exit 130 is retained in `controller-cancellation.json`, separately from any
|
||||
unfinished child result. Corrected full runs use `18-25` / `18-26` and source
|
||||
evidence under `build/ics55-tiny-2026-10-13-18-25-f3e42d54c18b/meta/tiny-r2-p7/`.
|
||||
|
||||
The corrected full Icarus attempts under `18-26` reached the watchdog-reset
|
||||
stage after reporting all first-boot peripherals, but both exhausted the
|
||||
36,000-second wall-clock budget with exit 124 and no terminal PASS. Those
|
||||
results remain FAIL. A focused test uses the real WDG APB wrapper, command
|
||||
mailboxes, Tiny APB bridge, clock backend, reset tree and RCU, and verifies two
|
||||
successive hardware watchdog resets, retained RCU cause and cleared functional
|
||||
state in both simulators. It does not replace the full firmware gate.
|
||||
The exact retained `simv` and firmware were replayed under
|
||||
`sim/iverilog/attempt-2026-10-14-04-50/` with `timeout --foreground 72000s vvp -i`,
|
||||
the same `+max_cycles=30000000 +tiny_jtag_smoke` and firmware path. The
|
||||
maintainer then intentionally interrupted both replays with exit 130 and moved
|
||||
this long-running full-Icarus gate to the final Tiny phase. The logs and
|
||||
interrupted `result-sim.json` records are retained as unrun/partial evidence;
|
||||
they cannot satisfy the P7 terminal verdict. `-i` enabled unbuffered standard
|
||||
IO; it did not change the design or acceptance workload. No synthesis,
|
||||
simulator compilation or firmware build was repeated for the replay.
|
||||
|
||||
PIDs are diagnostics in a particular execution namespace. Absence from another
|
||||
tool invocation's process list does not prove termination. Keep long commands
|
||||
attached to their execution sessions and use terminal result JSON plus strict
|
||||
log checks. `run_flow.py` records child/parent PIDs and closes results on caught
|
||||
exceptions; SIGKILL or host loss can still leave a running record. Such a record
|
||||
never counts as PASS. NFS clock-skew warnings are retained in the build logs.
|
||||
Cancellation now writes an interrupted checkpoint before process-group cleanup
|
||||
and ignores a second termination signal during that cleanup. The final result
|
||||
records the child's exit code and whether cleanup remains pending; the repeated
|
||||
signal/TERM-ignoring-child regression passes. An external executor can still
|
||||
kill a process before it handles a signal, so controller cancellation evidence
|
||||
must not be mistaken for a fabricated child exit result.
|
||||
|
||||
The ledger records the final pass/fail/unrun matrix. Human review of that matrix,
|
||||
the diff and remaining qualification boundaries is the P7 acceptance gate.
|
||||
The generated `audit.py` under the corrected full-run evidence directory reads
|
||||
all source configurations' terminal results, strict Tiny markers, P7 lifecycle
|
||||
observations, unchanged P6 workload/wire records, JTAG, paired firmware hashes,
|
||||
macro audit, netlist boot and STA artifacts. It launches no hardware flow and
|
||||
writes `acceptance.json`; a pending/missing/failed input cannot produce PASS.
|
||||
@@ -0,0 +1,402 @@
|
||||
# TINY-R2-P5 concurrent fabric
|
||||
|
||||
This implements the approved P5 preflight on
|
||||
`3131762b35e0ebfcd196395f955e7c1005bd18e7`, using frozen specification blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4`. The default is Tiny/ICS55 SAFE24
|
||||
with its present PLL parked off; IHP130/no PLL remains compatibility.
|
||||
The [ledger](tiny-soc-verification.md) separates phase evidence from approval.
|
||||
Historical campaigns and their limitations remain below. The P1 correction
|
||||
has its own source and validation scope; no P6, frequency or physical
|
||||
qualification is implied.
|
||||
|
||||
## P1 protocol correction (2026-10-11)
|
||||
|
||||
This correction starts from committed `4e6ab1a6fb445521703f0bfa412d3a1e8a38cd69`
|
||||
and the unchanged frozen specification. The preceding `09-30` campaign's
|
||||
`final-evidence.json` records two reset protocol failures and stale publication
|
||||
bindings even though ordinary regressions and matched-image replay passed.
|
||||
Those results do not qualify this corrected RTL.
|
||||
|
||||
Target reset cancels the downstream session while preserving the live
|
||||
upstream session. A reset sampled in Address/Response latches the abort path;
|
||||
releasing the target cannot replay its cancelled address or data. Already
|
||||
captured R/B responses remain in the Common spills with unchanged VALID,
|
||||
payload, ID and order. Only fabric/system reset clears those buffers. The
|
||||
downstream stability assertions follow the target's own reset; upstream
|
||||
stability assertions remain enabled throughout target-only reset.
|
||||
|
||||
A nine-bit count tracks captured read beats, including buffered and already
|
||||
retired beats. Missing DECERR beats append through the same spill until the
|
||||
original ARLEN+1 count is met; RLAST belongs only to the final beat. AbortWrite
|
||||
accepts/discards remaining upstream W beats before creating one DECERR B.
|
||||
Captured-B state prevents duplicate responses and preserves an already held
|
||||
successful completion. Fault metadata is captured from the first erroneous
|
||||
response beat, preserving earlier SLVERR over a subsequent reset DECERR;
|
||||
fault counting remains once per terminal transaction. Fully captured successful
|
||||
responses do not become reset faults.
|
||||
|
||||
The reset fixture drives stimulus away from sampling edges and independently
|
||||
checks R/B stability, exact beat counts, W-before-B ordering, one completion,
|
||||
credit release and first-error metadata. Its 28 cases include 16-beat SRAM/XPI
|
||||
traffic, a production APB bridge, three production DMA-master drain cases,
|
||||
target reset held through completion and early target release. A separate
|
||||
formal mode varies target reset arbitrarily and proves response/ownership,
|
||||
beat-count and W/B ordering properties by induction. The normal formal mode
|
||||
and its fixed-response expectations remain intact. Publication bindings retain
|
||||
complete terminal/fault predicates, with negative tests for premature
|
||||
completion and response flushing; the reviewed publication SHA is unchanged.
|
||||
|
||||
Evidence belongs under
|
||||
`build/ics55-tiny-2026-10-11-23-35-b4aa59f3e5d9/meta/tiny-r2-p5-p1/`.
|
||||
Final focused checks precede one full Pytest and one PR execution per Tiny
|
||||
PDK. No matched-image replay is required to claim this bounded correctness
|
||||
repair; historical workload measurements retain their source attribution.
|
||||
Validation completed on 2026-10-12; the ledger retains human review pending.
|
||||
Runtime peripheral-reset controls/quiescence remain P7, and the existing
|
||||
five-edge reset leaves remain unchanged. No shared DMA, public ABI, profile,
|
||||
dependency, warning baseline or metrics policy changes are included.
|
||||
|
||||
The final technical input digest is
|
||||
`f670789a2379a8d2e6c59f5ecd714ca0237bb6f1cfe749a2f29b0794d356b5f0`.
|
||||
`source.json` preserves the 2011 inputs and locked tools; `evidence.json`
|
||||
rechecks their identity and binds all gate/fixture/flow artifacts. Focused
|
||||
validation passes 101 tests; full Pytest passes 1685 with one optional `pypdf`
|
||||
skip and no failures. Counts overlap. ICS55/IHP130 PR commands each ran once;
|
||||
their Tiny nightly dry-run matrices match, so the same gates were not repeated.
|
||||
All six ordinary simulations satisfy command success, the Tiny success marker
|
||||
and forbidden-marker checks. The scoped reset fixture and formal checks are
|
||||
additional protocol evidence, not physical or XPI-device qualification.
|
||||
|
||||
| PDK / balanced recipe | Cells | Library area | Max WNS / TNS (ns) | Min WNS / TNS (ns) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| ICS55 | 245037 | 1910664.100799 | -70.04 / -1151596.25 | 0 / 0 |
|
||||
| IHP130 | 259394 | 9911158.202394 | -127.01 / -3120300.50 | 0 / 0 |
|
||||
|
||||
Current physical-flow observations are under
|
||||
`build/ics55-tiny-2026-10-11-23-35-42d5beccb726/` and
|
||||
`build/ihp130-tiny-2026-10-11-23-35-bff91e3529ba/`, in `meta/metrics.json`
|
||||
and `sta/opensta/{timing_metrics.rpt,p4-clock-bindings.rpt,opensta.log}`.
|
||||
Both mapping checks retain four groups, 32 macros and CPU/main SRAM on SYS.
|
||||
Timing remains observational and unclosed; library area is not routed die area
|
||||
and zero observed min violations do not constitute PVT/hold signoff. Lint
|
||||
signature/count sets are identical to `09-30` (470/414 new against the unchanged
|
||||
ICS55/IHP130 baselines, zero increased). Successful ABC Liberty-cache fallback
|
||||
and NFS clock-skew observations remain logged. No baselines were regenerated.
|
||||
|
||||
Commands used the locked activation, `BUILD_TIMESTAMP=2026-10-11-23-35` and
|
||||
`JOBS=3`. The `run_flow.py` JSON/log pairs in the correction evidence root retain
|
||||
every exact command: `focused`, `quality`, `pytest-full`, `regress-ics55`,
|
||||
`regress-ihp130`, `metrics-ics55`, `metrics-ihp130`, four `dry-run-*` records
|
||||
and `audit-result`. The principal acceptance commands were:
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
export BUILD_TIMESTAMP=2026-10-11-23-35 JOBS=3
|
||||
make rtl-format-check rtl-style-check-all rtl-readiness-check-all
|
||||
ruff check .
|
||||
python3 -m pytest -q --tb=short --basetemp=build/ics55-tiny-2026-10-11-23-35-b4aa59f3e5d9/meta/tiny-r2-p5-p1/tests-full
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
make CONFIG=configs/ci/ihp130-tiny.mk SOC=TINY PDK=IHP130 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
git diff --check
|
||||
```
|
||||
|
||||
New executions must select a fresh timestamp/evidence directory. New matched
|
||||
workload replay, compiler experiments, full-function C netlist qualification,
|
||||
PDF build/visual promotion, CDC/RDC, extracted PVT/MMMC and place/route were
|
||||
not run. No performance, new operating-frequency or complete-product claim is
|
||||
made by this correction. Error completion does not roll back downstream writes
|
||||
or peripheral side effects that committed before reset.
|
||||
|
||||
## Target-local reset repair (2026-10-11)
|
||||
|
||||
This is the superseded first attempt. Its focused tests passed but omitted
|
||||
required protocol checks; the later `09-30` campaign and independent monitors
|
||||
rejected it. The following description records that attempted behavior, not
|
||||
the corrected implementation above.
|
||||
|
||||
The P5 review found that a target reset was previously used only as an
|
||||
admission enable while an accepted controller session remained live. The
|
||||
attempt carried the explicit per-target reset leaf into each controller.
|
||||
Admission and downstream AXI VALID/W/RREADY are blocked while that leaf is
|
||||
asserted. An accepted Address or Response session changes to an abort response
|
||||
and returns one DECERR RLAST or B response with the saved owner and ID; the
|
||||
response remains held until the upstream terminal handshake. Response spill
|
||||
registers flush during the target reset, so an old downstream response cannot
|
||||
be replayed. The normal terminal handshake releases the fabric owner credit
|
||||
and records the reset termination as one fault event.
|
||||
|
||||
The focused reset-isolation fixture covers an accepted SRAM read held before
|
||||
response and an accepted XPI/APB write held before W, under both Icarus and
|
||||
Verilator. It checks DECERR termination, no stale response replay, and owner
|
||||
credit release. These local reruns are separate from the earlier matched-image
|
||||
campaign; the campaign evidence and PPA/STA attribution remain unchanged until
|
||||
a new approved evidence capture is made. The retained focused test output is
|
||||
under `build/ics55-tiny-2026-10-10-18-58-b4aa59f3e5d9/meta/tiny-r2-p5/reset-repair-tests/`.
|
||||
|
||||
## Ownership and bounds
|
||||
|
||||
The three ingress slots are CPU slow path 0, central DMA 1 and reserved SDIO 2.
|
||||
Only slots 0/1 have product producers. CPU has one combined read/write credit;
|
||||
DMA and the reserved interface each have one read and one write credit.
|
||||
The real DMA already reserves complete write data before starting a burst;
|
||||
its shared scheduler and all request/channel assignments are unchanged.
|
||||
|
||||
Targets 0–3 directly attach the existing SRAM group frontends through Common
|
||||
AXI connectors. Target 4 is XPI memory. Targets 5–20 follow the existing APB
|
||||
peripheral order, with GPIO's two windows sharing its one branch. Targets 21/22
|
||||
are the unchanged DECERR/SLVERR responders. The generator emits the decoder
|
||||
and sixteen single-peripheral bridge instances from canonical topology.
|
||||
There is no product-wide APB or external transaction lock.
|
||||
|
||||
Each target admits one combined transaction and saves owner, direction and
|
||||
address attributes on the upstream address handshake. Admission reserves both
|
||||
target and ingress direction, even while the downstream address is stalled.
|
||||
Owner round robin advances on admission; the chosen owner's direction
|
||||
preference alternates when both directions compete. W waits for saved AW
|
||||
ownership and downstream AW acceptance, and stops after the terminal data beat.
|
||||
Bounded Common response spill registers isolate held R/B values. Ownership and
|
||||
ingress credit last through the upstream B/RLAST handshake, including buffered
|
||||
terminal responses. A continuously eligible owner can be bypassed by at most
|
||||
two other admissions; progress requires clocks and peer completion.
|
||||
|
||||
Local CPU I/D, group arbitration, P4 response reservations and main SRAM macro
|
||||
paths are unchanged. The local uncontended bound remains three SYS cycles,
|
||||
and the P4 external SRAM streaming fixture still requires one beat per cycle.
|
||||
All new logic uses SYS; APB bridges follow their existing peripheral reset
|
||||
leaves. Target reset must be released for admission. System reset invalidates
|
||||
all buffered sessions without clearing SRAM payload. Hart reset drains CPU
|
||||
work only. Runtime peripheral resets still require P7's quiescence controls.
|
||||
|
||||
## Faults and public compatibility
|
||||
|
||||
Each target retains its first failed captured read beat's address/response
|
||||
until terminal upstream completion; a successful final beat cannot erase it.
|
||||
Write errors retain the accepted AW address. Six external direction events and
|
||||
two local CPU events feed the collector. CPU frontend errors carry SLVERR;
|
||||
external errors propagated through AHB are not counted again locally.
|
||||
|
||||
The collector increments the existing count by every simultaneous event,
|
||||
using four-bit multiplicity and a 33-bit saturating sum. It selects metadata
|
||||
by ascending owner, CPU instruction before data, then read before write.
|
||||
Equal keys use stable input order. SYSCTRL preserves a valid first snapshot;
|
||||
W1C clears validity only and a simultaneous hardware event wins over clear.
|
||||
FAULT_MASTER adds reserved owner 2 without changing offset or owner 0/1 meanings.
|
||||
FAULT_DETAIL remains raw AXI response 2/3. The existing HAL byte-sized owner
|
||||
field needs no change. No SDK API, register generator, interrupt, DMA channel,
|
||||
capability or pad assignment is added.
|
||||
|
||||
The old CPU/DMA wait registers retain their predicate: a requesting owner with
|
||||
no address handshake in that cycle counts once. R2_P5_FABRIC records separate
|
||||
active-target maxima, DMA simultaneous read/write ownership and simultaneous
|
||||
read/write beat handshakes. These are testbench observations. The original
|
||||
P3/P4 record formats and evidence retain their own identities.
|
||||
|
||||
## Verification and reproducibility
|
||||
|
||||
Focused protocol tests use all three owner slots, saved-address perturbations,
|
||||
W-before-AW, held addresses/data/responses, independent control branches,
|
||||
same-target contention and 96 deterministic randomized reads. Mixed-response
|
||||
bursts align two terminal faults while their final responses are OKAY.
|
||||
SYSCTRL tests cover multi-event count, owner 2, hardware-over-W1C and saturation.
|
||||
The saturation test seeds the Common counter register, then exercises the
|
||||
real adder and readback; it does not simulate billions of events.
|
||||
|
||||
The system fixture instantiates production retrosoc_tiny, CPU, DMA, SRAM,
|
||||
bridges and SYSCTRL. Only the XPI boundary is replaced with a controllable
|
||||
verification endpoint and a fixture-only reset ROM. Real DMA copies B2 to B3
|
||||
with concurrent read/write beats and CPU readback checks. With an XPI mapped
|
||||
response held, SRAM code and SYSCTRL access continue. A held XPI APB write
|
||||
then verifies independent controls and hart-reset isolation. Finally CPU aborts
|
||||
a held DMA read, checks that BUSY survives accepted work, releases the response
|
||||
and verifies ABORTED. Ordinary regressions retain real pin-level XPI/NOR models.
|
||||
This fixture is neither a product Boot ROM nor an XPI-device qualification.
|
||||
|
||||
The first fixture attempted hart reset while holding the XPI memory response;
|
||||
an accepted CPU instruction also needed that target, so reset correctly waited
|
||||
for drain. The corrected isolation case retains DMA at the independent APB
|
||||
branch and permits CPU progress. Other development attempts preserve sv2v
|
||||
diagnostics separately from converted RTL and observe declared interface
|
||||
instances rather than module-modport aliases for Icarus compatibility.
|
||||
|
||||
Yosys induction checks production target ownership, response retention,
|
||||
terminal-fault attribution and service-count fairness. A combinational proof
|
||||
checks the collector's count and lexicographic metadata selection for arbitrary
|
||||
event vectors. These are scoped control proofs, not full-chip formal signoff.
|
||||
|
||||
The P5 replay entrypoint uses the unchanged P3 flat/banked images referenced by
|
||||
the repaired P4 report:
|
||||
`build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/report.json`.
|
||||
The old reports retain their original 4db27524-based snapshot attribution;
|
||||
preflight matched all 1972 technical inputs to the committed P5 starting point.
|
||||
P5 report identity, source/configuration/tool hashes and observations are new.
|
||||
Parameters stay 1024 words, four jobs, 4096 CPU iterations and seed 0x12345678.
|
||||
Each Verilator image runs once and banked Icarus once; all banked observations
|
||||
must agree. There is no frozen overall speedup requirement or compiler/layout
|
||||
experiment. Different-bank concurrency is proved separately because the
|
||||
retained banked placement concentrates DMA storage in B3.
|
||||
|
||||
Fresh development evidence begins at
|
||||
`build/ics55-tiny-2026-10-10-18-25-b4aa59f3e5d9/meta/tiny-r2-p5/`.
|
||||
The completed campaign and its monitor-only follow-up are recorded below.
|
||||
Documentation remains here rather than in generated directories.
|
||||
The Tiny draft/source extractor follows P5 routing and the fault field width;
|
||||
its reviewed publication SHA and PDF status are not advanced.
|
||||
|
||||
## Completed campaign and monitor correction
|
||||
|
||||
The final evidence root is
|
||||
`build/ics55-tiny-2026-10-10-18-58-b4aa59f3e5d9/meta/tiny-r2-p5/`.
|
||||
`source.json` binds the initial 2010-input campaign to combined ICS55/IHP130
|
||||
digest `e85f4245883bf35f152d607480adf48edcf49debadb46d8b0bde92050a792b11`.
|
||||
Both Tiny PR regressions, full Pytest and the first three image executions
|
||||
passed on that snapshot. The initial aggregation in `report-result.{json,log}`
|
||||
correctly failed: Icarus reported active-target maxima one greater than
|
||||
Verilator in all eight banked windows, while every other sample was identical.
|
||||
|
||||
The locked Icarus 13 installation miscounts the temporary expression
|
||||
`$countones(~a_23_bit_vector)`. `countones_probe.sv` and its retained log
|
||||
demonstrate an expected count 1 returning 3/6, while a named vector and explicit
|
||||
bit counting return 1. The correction counts the declared 23 bits explicitly,
|
||||
rejects unknown target states, and adds an opt-in count 0..23 self-check. No
|
||||
postprocessing subtraction, relaxed comparison, tool upgrade or DUT fix is used.
|
||||
|
||||
`monitor-source.json` captures the final combined digest
|
||||
`0f3ed21f6fd6e932ff2532aab8c9964e71cf4b972e4c27e2c8ca6ab1f22c1015`.
|
||||
Its only technical difference from the initial capture is
|
||||
`rtl/tiny/dv/retrosoc_tiny_tb.sv`, inside P5 opt-in observation/self-check code.
|
||||
The DUT, firmware, verification fixtures, policies and tool inputs are identical.
|
||||
The ordinary regression commands do not enable this branch, and netlist boot
|
||||
excludes it. Their results, full-suite results and PPA retain their original
|
||||
snapshot attribution; they were not rerun or relabeled as new executions.
|
||||
The audit checks this exact single-file delta and the original command flags.
|
||||
|
||||
Both Verilator images and banked Icarus were rebuilt/replayed after the fix,
|
||||
and the monitor self-check passed on both new models. The final ICS55-only
|
||||
replay input digest is
|
||||
`df14713ed7177d988d0e3fa0a038984589584788eda994dd7480f01a8dfcab7c`.
|
||||
`report-final.{json,log}` and `report.json` confirm exact equality of all banked
|
||||
observations across simulators, including the corrected active-target statistic.
|
||||
`monitor-diagnosis.json` preserves the original discrepancy, logs and input
|
||||
identity. Final model copies are retained beside their attempt records and
|
||||
bound by `model-backup-*.json`; the initial Icarus model is separately retained.
|
||||
|
||||
| Gate | Retained result | Scope/outcome |
|
||||
| --- | --- | --- |
|
||||
| Focused development suite | Earlier `18-25` root, `focused-final.{json,log}` | 106 passed before final campaign |
|
||||
| Initial quality | `quality.{json,log}` | Ruff, diff, RTL format/style/readiness pass; 11.524 s |
|
||||
| Full Pytest | `pytest-full.{json,log}` | 1679 passed, optional `pypdf` skip; 3867.891 s; original snapshot |
|
||||
| Tiny ICS55 PR | `regress-tiny-ics55.{json,log}` | Pass; 4273.573 s; original snapshot |
|
||||
| Tiny IHP130 PR | `regress-tiny-ihp130.{json,log}` | Pass; 3028.340 s; original snapshot |
|
||||
| Initial image executions | `replay-verilator` / `replay-iverilog` results | Commands pass; 609.465/5952.278 s; cross-simulator aggregation fails as above |
|
||||
| Monitor follow-up quality | `monitor-quality.{json,log}` | Pass; 11.714 s |
|
||||
| Count self-checks | `monitor-check-{verilator,iverilog}.{json,log}` | Pass; instrumentation-only, not firmware acceptance |
|
||||
| Final image executions | `replay-verilator-monitor` / `replay-iverilog-monitor` results | Pass; 618.974/5978.016 s; one run per selected image |
|
||||
| Final report and audit | `report-final.{json,log}`, `report.json`, `evidence.json`, `audit.py` | Measurement complete; source-bound functional validation complete, review pending |
|
||||
|
||||
All six ordinary simulations satisfy command success, configured SIM_TEST_PASS
|
||||
and absence of forbidden error markers. In the final full suite, six P4 SRAM
|
||||
fixtures preserve three-cycle local latency and one-cycle streaming spacing;
|
||||
two P4 CPU fixtures, two P5 fabric fixtures, two real-CPU/DMA system fixtures
|
||||
and three scoped formal logs pass. The system fixture reports 13 simultaneous
|
||||
DMA read/write beat cycles and 27 independent control completions on both tools,
|
||||
with hart-reset isolation and abort drain. SYSCTRL tests additionally check
|
||||
multiple faults, reserved owner 2, raw detail, clear precedence and saturation.
|
||||
These are functional results, not physical or XPI-device qualification.
|
||||
|
||||
## Measurements and qualification limits
|
||||
|
||||
The final runs preserve the immutable P3 image identities and compare them
|
||||
with repaired P4 measurements, without changing compiler or placement:
|
||||
|
||||
| Workload | Flat P4 → P5 cycles | Banked P4 → P5 cycles |
|
||||
| --- | ---: | ---: |
|
||||
| Empty | 69 → 69 | 66 → 66 |
|
||||
| CPU | 73911 → 73911 | 73914 → 73914 |
|
||||
| CPU copy | 102568 → 102568 | 86214 → 86214 |
|
||||
| DMA burst1 | 91306 → 65527 | 89365 → 65502 |
|
||||
| DMA burst16 | 17897 → 16974 | 17317 → 15802 |
|
||||
| CPU/DMA contention | 299881 → 299990 | 299633 → 299738 |
|
||||
| TCD contention | 299878 → 300027 | 299645 → 299750 |
|
||||
| Chunk256 | 361285 → 361514 | 359570 → 361355 |
|
||||
|
||||
The flat burst16 window records a maximum of three active targets, 124 cycles
|
||||
with simultaneous DMA read/write ownership and 48 simultaneous read/write beat
|
||||
cycles. Banked DMA stays in B3 and has zero DMA read/write overlap; up to two
|
||||
targets are active because independent CPU control can overlap that bank.
|
||||
The separate system fixture establishes different-bank DMA concurrency.
|
||||
CPU/copy cycles are unchanged. Small contention/TCD increases and the 0.50%
|
||||
banked chunk256 increase remain visible; no universal speedup is claimed.
|
||||
|
||||
Synthesis/STA observations for the unchanged DUT use
|
||||
`build/ics55-tiny-2026-10-10-18-58-42d5beccb726/` and
|
||||
`build/ihp130-tiny-2026-10-10-18-58-bff91e3529ba/`.
|
||||
Both pass synthesis, netlist boot and the existing 32-macro/direct-SYS binding
|
||||
checks. Reports are `meta/metrics.json`, `sta/opensta/timing_metrics.rpt`,
|
||||
`sta/opensta/p4-clock-bindings.rpt` and `sta/opensta/retrosoc_sta.log`.
|
||||
|
||||
| PDK | Cells | Library area | Max WNS / TNS (ns) | Min WNS / TNS (ns) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| ICS55 | 241309 | 1906156.940799 | -64.75 / -932689.50 | 0 / 0 |
|
||||
| IHP130 | 256995 | 9888378.712794 | -111.93 / -2594456.50 | 0 / 0 |
|
||||
|
||||
Library area grows 5.56%/6.95% versus repaired P4. Max timing margins worsen;
|
||||
timing remains unclosed and observational before the final product campaign.
|
||||
Library area is not routed die area, and zero observed min violations is not
|
||||
PVT/hold signoff. No new timing exception or rate is introduced.
|
||||
|
||||
The unchanged warning baselines report 469/413 new signatures for ICS55/IHP130,
|
||||
zero increased and zero resolved. Relative to repaired P4, two new signatures
|
||||
are intentional empty `owner_idle_o`/`target_idle_o` connections; their future
|
||||
lifecycle use and verification visibility are documented at the instances.
|
||||
The former unused interface `aresetn` signature disappears because target
|
||||
admission now consumes it. There is no new width/latch signature. The known
|
||||
NFS clock-skew warning and successful ABC Liberty-cache fallback remain logged.
|
||||
No warning baseline or metrics policy was changed.
|
||||
|
||||
Mini behavioral compatibility retains its earlier P4 evidence and source
|
||||
identity. The audit rechecks the unchanged shared/Mini/SDK/configuration inputs;
|
||||
there is no new Mini execution or physical claim. No C/H implementation or
|
||||
MISRA deviation changed. The P3 compiler matrix and three cold repetitions,
|
||||
full C netlist campaign, PDF build/visual checks, CDC/RDC/PVT/MMMC, place/route,
|
||||
high-rate qualification and P6+ work were not performed. Only the concretely
|
||||
affected image measurements were repeated for the monitor defect.
|
||||
|
||||
## Executed commands
|
||||
|
||||
Commands used the locked activation and `BUILD_TIMESTAMP=2026-10-10-18-58`,
|
||||
`JOBS=3`. `scripts/run_flow.py` retains the exact outer commands and JSON/log
|
||||
results named above. New evidence is under `meta/tiny-r2-p5`; source snapshots,
|
||||
tool identities, input digests, models, images and raw logs remain separate.
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
export BUILD_TIMESTAMP=2026-10-10-18-58 JOBS=3
|
||||
make rtl-format-check rtl-style-check-all rtl-readiness-check-all
|
||||
ruff check .
|
||||
git diff --check
|
||||
python3 -m pytest -q --basetemp=build/ics55-tiny-2026-10-10-18-58-b4aa59f3e5d9/meta/tiny-r2-p5/tests-full
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --soc TINY --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 SIMU=VERILATOR SOC_SIM_TIME=21600 \
|
||||
TINY_P5_REFERENCE=build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/report.json \
|
||||
TINY_P5_CASES=perf-o2-plain-flat,perf-o2-plain-banked tiny-r2-p5-replay
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 SIMU=IVERILOG SOC_SIM_TIME=21600 \
|
||||
TINY_P5_REFERENCE=build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/report.json \
|
||||
TINY_P5_CASES=perf-o2-plain-banked tiny-r2-p5-replay
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 tiny-r2-p5-report
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
make CONFIG=configs/ci/ihp130-tiny.mk SOC=TINY PDK=IHP130 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
PYTHONDONTWRITEBYTECODE=1 python3 build/ics55-tiny-2026-10-10-18-58-b4aa59f3e5d9/meta/tiny-r2-p5/audit.py
|
||||
```
|
||||
|
||||
Tiny PR/nightly definitions matched and were not executed twice. The first
|
||||
report attempt failed; only the monitor-corrected executions qualify the final
|
||||
cross-simulator report. The original cold executions are not a three-repeat
|
||||
qualification campaign. No commit, staging, push, PR or automatic next-phase
|
||||
transition belongs to this implementation.
|
||||
@@ -0,0 +1,387 @@
|
||||
# TINY-R2-P4 local CPU/SRAM implementation
|
||||
|
||||
## Approved throughput repair (2026-10-10; validated, review pending)
|
||||
|
||||
The maintainer approved the eight-file P4 throughput-repair preflight after
|
||||
the read-only review identified the external frontend's per-beat bubbles.
|
||||
This follow-up remains P4; it does not enable P5 target concurrency.
|
||||
The initial implementation and its measurements below are retained historical
|
||||
evidence for the pre-repair snapshot, not qualification of the changed RTL.
|
||||
Fresh evidence is under
|
||||
`build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/`.
|
||||
|
||||
The group now reserves two response slots for its external client, counting
|
||||
both queued completions and a macro read still in flight. A response pop may
|
||||
free capacity on the same edge as the next issue. The macro's saved owner/bank
|
||||
still selects the captured read value; FIFO data cannot be overwritten by
|
||||
later local accesses. A same-client pending read prevents a simultaneous write
|
||||
commit into the single-push response FIFO. Local I/D keep one operation each
|
||||
and their original completion pipeline.
|
||||
|
||||
The external frontend separates issued and retired read positions. W uses a
|
||||
two-entry Common FIFO containing captured address, data and byte strobes.
|
||||
Only captured legal beats enter arbitration. Invalid strobes or LAST retain
|
||||
the existing error policy, including earlier committed beats and later legal
|
||||
beats after an invalid strobe. B waits for all queued legal writes and their
|
||||
commit responses. External transaction ownership still lasts through B/RLAST.
|
||||
These are small register queues, not additional user SRAM or new macros.
|
||||
|
||||
Acceptance adds consecutive 16-beat read/write handshakes at one SYS cycle per
|
||||
beat after startup, without local competition or bus backpressure. Logs retain
|
||||
first-beat latency, total transfer time and final-W-to-B delay. Directed checks
|
||||
fill/drain queues, stop READY, interleave local service, retain old read values
|
||||
across local writes, exercise buffered malformed writes and drop stale queued
|
||||
responses on system reset. Induction checks response conservation/capacity in
|
||||
addition to held-response stability and the existing service-count fairness.
|
||||
The unchanged CPU debug/reset, discovery/counters and both real-PDK macro
|
||||
fixtures remain required.
|
||||
|
||||
Use the same immutable P3 flat/banked images and parameters. Each selected
|
||||
Verilator image runs once; banked Icarus runs once. Compare both with their P3
|
||||
samples and the pre-repair P4 report. The repair requires burst-16 cycles below
|
||||
36713/36489 respectively, truthful reporting of all other workload deltas and
|
||||
identical banked results across simulators. It does not promise P3 cycle parity
|
||||
or change compiler/layout settings. Existing shared Mini debug inputs are
|
||||
unchanged by this repair; matching prior compatibility evidence is retained.
|
||||
|
||||
### Repair results and provenance
|
||||
|
||||
The campaign is complete for review. `source.json`, `report.json`, `audit.py`
|
||||
and `evidence.json` in the fresh evidence root bind 1972 technical inputs,
|
||||
six fresh Tiny regression simulations, three matched-image executions,
|
||||
six real/behavioral SRAM fixtures, two CPU fixtures and control induction.
|
||||
The combined ICS55/IHP130 input digest is
|
||||
`58daf68fbb9dee199b3085a73ef07d22eb3de6d00ba875c462e85b76b6091a0d`;
|
||||
the ICS55 replay input digest is
|
||||
`a96a129ffc02d0d38fd2eee7ed8fb62893828db3602bbd4459e0a71ffce0c35f`.
|
||||
Only the approved six technical files differ from the preceding P4 snapshot;
|
||||
the other two changes are this runbook and the ledger. No commit or staging
|
||||
operation is part of this campaign.
|
||||
|
||||
All six SRAM runs record `read_gap_max=1 write_gap_max=1 beats=16`, with first
|
||||
R at three cycles after AR and final R at cycle18; W begins one cycle after
|
||||
AW, final B is at cycle20, four cycles after final W. These are standalone
|
||||
uncontended protocol measurements, not end-to-end DMA or physical timing.
|
||||
All six retain `local_latency_max=3`. The new queue checks cover full-response
|
||||
backpressure, local writes to already captured read addresses, W contention,
|
||||
buffered malformed writes, and both queued-R and accepted-but-uncommitted-W
|
||||
system resets. CPU debug/patch/hart-reset and induction pass in the final suite.
|
||||
|
||||
| Gate | Result under the fresh evidence root | Outcome |
|
||||
| --- | --- | --- |
|
||||
| Final Ruff, diff, RTL format/style/readiness | `quality-pass.{json,log}` | Pass |
|
||||
| Full Pytest | `pytest-full.{json,log}` | 1659 passed, one optional `pypdf` skip; 3903.061 s |
|
||||
| Tiny ICS55 PR | `regress-tiny-ics55.{json,log}` | Pass; 3396.035 s |
|
||||
| Tiny IHP130 PR | `regress-tiny-ihp130.{json,log}` | Pass; 2340.150 s |
|
||||
| Verilator, both immutable images once | `replay-verilator.{json,log}` | Pass; 390.698 s |
|
||||
| Icarus, immutable banked image once | `replay-iverilog.{json,log}` | Pass; 5154.223 s |
|
||||
| Cross-simulator report | `report-result.{json,log}`, `report.json` | Complete; all banked observations identical |
|
||||
| Source/artifact audit | `evidence.json`, `audit.py` | Pass; review/phase acceptance pending |
|
||||
|
||||
The initial `quality-final.{json,log}` is a retained failed development attempt:
|
||||
the style gate required `s_req_accept`/`s_resp_accept` abbreviations. The names
|
||||
were corrected before the final source snapshot and all long gates. The first
|
||||
29 focused checks and additional queued-W-reset check also passed; final-suite
|
||||
logs qualify the final technical snapshot. No failed attempt is relabeled.
|
||||
|
||||
| Workload | Flat pre-repair P4 → repaired P4 | Banked pre-repair P4 → repaired P4 |
|
||||
| --- | ---: | ---: |
|
||||
| Empty | 69 → 69 | 66 → 66 |
|
||||
| CPU | 73911 → 73911 | 73914 → 73914 |
|
||||
| CPU copy | 102568 → 102568 | 86214 → 86214 |
|
||||
| DMA burst1 | 91306 → 91306 | 89365 → 89365 |
|
||||
| DMA burst16 | 36713 → 17897 | 36489 → 17317 |
|
||||
| CPU/DMA contention | 303493 → 299881 | 299633 → 299633 |
|
||||
| TCD contention | 303702 → 299878 | 299645 → 299645 |
|
||||
| Chunk256 | 377705 → 361285 | 376970 → 359570 |
|
||||
|
||||
Burst16 cycles decrease 51.25%/52.54%, satisfying the approved repair criterion.
|
||||
They remain 8.34%/4.81% above the original P3 16520/16523 cycles. Burst1 still
|
||||
retains the earlier P4 overhead versus P3; this repair does not claim universal
|
||||
baseline parity. Flat local maximum is four cycles in contended windows, with
|
||||
17697 eligible bank-conflict cycles; banked maximum is three with zero conflicts.
|
||||
Uncontended local latency is still checked independently. Firmware checksums,
|
||||
parameters and each image's compiler/layout identity remain unchanged.
|
||||
|
||||
Fresh physical variants are
|
||||
`build/ics55-tiny-2026-10-10-15-15-42d5beccb726/` and
|
||||
`build/ihp130-tiny-2026-10-10-15-15-bff91e3529ba/`.
|
||||
Both pass synthesis, netlist boot and common-SYS/32-macro binding checks.
|
||||
Their `meta/metrics.json`, `sta/opensta/timing_metrics.rpt`,
|
||||
`sta/opensta/p4-clock-bindings.rpt` and `sta/opensta/retrosoc_sta.log` retain
|
||||
the matching observations:
|
||||
|
||||
| PDK | Cells | Library area | Setup WNS / TNS (ns) | Hold WNS / TNS (ns) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| ICS55 | 207029 | 1805809.700799 | -36.88 / -489807.34 | 0 / 0 |
|
||||
| IHP130 | 218773 | 9245382.228597 | -97.37 / -1640251.62 | 0 / 0 |
|
||||
|
||||
Setup remains unclosed; library area is not die area and zero observed hold
|
||||
slack violations are not physical signoff. Lint comparisons to the unchanged
|
||||
baselines report 468/412 new signatures for ICS55/IHP130, zero increased and
|
||||
zero resolved. Relative to pre-repair P4 there are exactly two additional
|
||||
signatures: intentionally unused FIFO `cnt_o`, and `s_full`, which is consumed
|
||||
by the verification assertions but unused in synthesis-oriented lint. No new
|
||||
width/latch warning is attributed to the repair. Warning and metrics policy
|
||||
remain observational and no baseline was edited.
|
||||
|
||||
Commands below used the same timestamp, with `scripts/run_flow.py` retaining
|
||||
outer command/result/log records. Standalone test artifacts use distinct
|
||||
`tests-focused`, `tests-reset` and `tests-full` directories under this variant.
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
export BUILD_TIMESTAMP=2026-10-10-15-15 JOBS=3
|
||||
python3 -m pytest -q tests/test_tiny_r2_p4.py --basetemp=build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/tests-focused
|
||||
python3 -m pytest -q 'tests/test_tiny_r2_p4.py::test_four_group_local_memory[BEHAV-iverilog]' --basetemp=build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/tests-reset
|
||||
ruff check .
|
||||
git diff --check
|
||||
make rtl-format-check rtl-style-check-all rtl-readiness-check-all
|
||||
python3 -m pytest -q --basetemp=build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/tests-full
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --soc TINY --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 SIMU=VERILATOR SOC_SIM_TIME=21600 \
|
||||
TINY_P4_REFERENCE=build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/report.json \
|
||||
TINY_P4_CASES=perf-o2-plain-flat,perf-o2-plain-banked tiny-r2-p4-replay
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 SIMU=IVERILOG SOC_SIM_TIME=21600 \
|
||||
TINY_P4_REFERENCE=build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/report.json \
|
||||
TINY_P4_CASES=perf-o2-plain-banked tiny-r2-p4-replay
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 tiny-r2-p4-report
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
make CONFIG=configs/ci/ihp130-tiny.mk SOC=TINY PDK=IHP130 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
PYTHONDONTWRITEBYTECODE=1 python3 build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/audit.py
|
||||
```
|
||||
|
||||
Tiny PR/nightly dry-runs match; no duplicate nightly execution was needed.
|
||||
The six fresh ordinary simulations all require `SIM_TEST_PASS`, including
|
||||
Tiny netlist boot, together with command success and no forbidden error marker.
|
||||
Mini's two prior behavioral results retain their original source attribution;
|
||||
the audit verifies that changed technical inputs are confined to Tiny and its
|
||||
tests. Mini synthesis/STA, the P3 compiler matrix, additional cold repetitions,
|
||||
C format/policy/host reruns, PDF generation, PVT/MMMC, CDC/RDC and place/route
|
||||
were not run for this repair. No C/H code or MISRA deviation changed. The
|
||||
full-suite optional PDF retrieval check remains skipped for missing `pypdf`.
|
||||
No new frequency, physical qualification or P5 authorization is claimed.
|
||||
|
||||
## Original implementation snapshot
|
||||
|
||||
This implements the approved [P4 contract](tiny-soc.md#tiny-r2-p4---dual-port-hazard3-and-four-bank-local-sram)
|
||||
from `4db27524a6282ca40d76b935415b89f043d6ea83`, specification blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4`. The maintainer approved the preflight
|
||||
and implementation. No P5 execution, dependency update, publication release or
|
||||
physical-frequency qualification is implied. Historical phase evidence remains
|
||||
in the [ledger](tiny-soc-verification.md).
|
||||
|
||||
## Architecture and lifecycle
|
||||
|
||||
Tiny uses locked `hazard3_cpu_2port`, preserving ISA, IRQ, debug, multiply and
|
||||
branch-prediction settings; A remains disabled. Separate I/D AHB frontends decode
|
||||
SRAM before the tagged slow-path merge. One accepted D operation spans all
|
||||
targets. Write data is captured in its AHB data phase; local stores complete
|
||||
after macro commit. Uncontended local completion is at most three SYS cycles.
|
||||
Slow errors retain two-cycle AHB completion. Instruction origin reaches the
|
||||
existing fabric fault path: only NOR boot/NSS0 may be fetched externally, and
|
||||
peripheral fetches cannot trigger register reads.
|
||||
|
||||
Four 32 KiB groups cover `0x30000000..0x3001ffff`, each with eight existing
|
||||
4 KiB macros and I/D/external round robin advancing only on macro issue.
|
||||
Per-client registers capture read responses before macro outputs change.
|
||||
External W waits and R/B backpressure do not lock local macro service.
|
||||
Continuously eligible requests wait for at most two other issues, conditional
|
||||
on progress rather than a wall-clock bound for stopped peers.
|
||||
|
||||
Each external frontend retains one transaction through B/RLAST and alternates
|
||||
read/write preference. A direction-tagged demux preserves the existing external
|
||||
fabric attachment. Whole-product different-target DMA read/write concurrency
|
||||
remains P5; standalone frontend concurrency is not that product qualification.
|
||||
|
||||
Hart reset requests debug halt, prevents new debug instruction injection, drains
|
||||
accepted local/slow operations and responses, then resets the hart/frontends.
|
||||
A terminal-cycle AHB overlap must still drain. SRAM/external frontends and
|
||||
unrelated DMA stay active. System reset invalidates pending responses without
|
||||
clearing SRAM payload. Five-edge release and Mini's default single-port reset
|
||||
behavior are preserved; shared debug only adds a pending-state output.
|
||||
|
||||
## ABI, physical bindings and observations
|
||||
|
||||
Shared SRAM register definitions are unchanged: 128 KiB, `BANK_COUNT=32`,
|
||||
`BANK_BYTES=4096`. Public counters count external AXI events, saturating sums
|
||||
of simultaneous events; stall cycles use OR across groups. Local CPU traffic
|
||||
is not silently added. `R2_AHB` observes the separate I/D ports. `R2_P4_LOCAL`
|
||||
records local completions, latency and address-admission waits; `R2_P4_BANK`
|
||||
records macro issues, eligible-client waits and conflict cycles (two or more
|
||||
eligible clients in a group). These are verification-only observations.
|
||||
|
||||
Macro `g,b` is `u_soc.u_sram.gen_group[g].u_group.gen_bank[b].u_ram.u_mem`,
|
||||
physical index `8*g+b`. IHP130 placement coordinates stay fixed while instance
|
||||
and supply hooks track both indices. CPU and all 32 macros remain directly on
|
||||
SYS24; ICS55 PLL stays off and IHP130 remains no-PLL compatibility. Mapping
|
||||
checks reject stale single-port/flat-bank hierarchies. STA remains observational,
|
||||
with no 96/192/240 MHz or physical signoff claim.
|
||||
|
||||
The Tiny publication extractor and affected draft prose/diagram follow the new
|
||||
bindings. No reviewed publication SHA, delivered PDF or release status advances.
|
||||
|
||||
## Acceptance and matched images
|
||||
|
||||
`tests/test_tiny_r2_p4.py` uses real IHP130/ICS55 macro models and a behavioral
|
||||
model on both simulators: all macro/group boundaries, byte masks, back-to-back
|
||||
AHB, independent groups, held responses, W-before-AW, bursts/malformed writes,
|
||||
discovery/counter semantics and reset payload retention. Deterministic readback
|
||||
uses seed `0x12345678`, 4096 write/read pairs per group. The actual CPU fixture
|
||||
checks mixed 16/32-bit cross-group fetch, FENCE.I, instruction faults, JTAG
|
||||
patch/resume, and reset with a held slow response plus an unrelated held B.
|
||||
Yosys induction proves group control fairness and retained responses with only
|
||||
macro payload abstracted. Normal Tiny firmware additionally executes code
|
||||
copied through the real DMA, then CPU-patched code, after completion/FENCE.I.
|
||||
Its helper is private acceptance assembly, not a new SDK API.
|
||||
|
||||
`tiny-r2-p4-replay` validates retained P3 images/logs, builds a fresh P4 model,
|
||||
and executes each selected image once. Image source/compiler/layout and new
|
||||
RTL/model identities are separate; hardware settings must match. Original P3
|
||||
same-source/three-cold-start rules are unchanged. `tiny-r2-p4-report` revalidates
|
||||
artifacts and requires identical banked-image results across the two simulators.
|
||||
|
||||
The reference is
|
||||
`build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/report.json`.
|
||||
Select `perf-o2-plain-flat` and `perf-o2-plain-banked` for Verilator and the banked
|
||||
image for Icarus. Parameters remain 1024 words, four jobs, 4096 CPU iterations,
|
||||
seed `0x12345678`, burst-1/16 DMA, TCD and chunk-256. Compare each unchanged
|
||||
binary with its own historical samples, not with a different compiler/layout.
|
||||
No fixed speedup is predeclared; latency/fairness requirements remain gates.
|
||||
|
||||
Development evidence begins under
|
||||
`build/ics55-tiny-2026-10-10-10-05-b4aa59f3e5d9/meta/tiny-r2-p4/`.
|
||||
Early fixture failures and corrected runs are retained separately. The final
|
||||
campaign below completes planned functional validation and measurements; human
|
||||
review/phase acceptance remain pending, including the DMA throughput tradeoff.
|
||||
|
||||
## Executed campaign and provenance
|
||||
|
||||
The evidence root above contains `source.json`, `evidence.json`, `audit.py` and
|
||||
`report.json`. The campaign snapshot contains 1972 unchanged technical inputs,
|
||||
base commit `4db27524a6282ca40d76b935415b89f043d6ea83` plus the retained patch and
|
||||
new-file archive, and locked tool/executable/archive identities. Its combined
|
||||
ICS55/IHP130 digest is
|
||||
`9fa311a5500711c99b006eacd95cdff04a74659d52b5b46640c42c49773a7f66`.
|
||||
The ICS55-only replay source set has digest
|
||||
`2f0d285186f84d41422d8381d09b0a01a2afc066dbd011a11ec7a8a85433ad0d`;
|
||||
these are different declared input sets, not conflicting identities.
|
||||
|
||||
The final audit rechecks all captured inputs, eight ordinary regression
|
||||
simulations, the three matched-image executions, six standalone memory runs,
|
||||
two actual-CPU runs and the group-control induction log. Ordinary firmware and
|
||||
model artifacts are hashed post-run; the campaign source hashes were captured
|
||||
before execution and rechecked afterward. Image/model identities and original
|
||||
P3 phase attribution are retained separately.
|
||||
|
||||
| Gate | Retained result under the evidence root | Outcome |
|
||||
| --- | --- | --- |
|
||||
| Format/style/readiness, C policy/host, Ruff/diff | `quality-final.{json,log}` | Pass; no new MISRA deviation; partial checks, not MISRA certification |
|
||||
| Full Pytest | `pytest-full.{json,log}` | 1659 passed, one optional `pypdf` environment skip; 3856.630 s |
|
||||
| Tiny ICS55 PR | `regress-tiny-ics55.{json,log}` | Pass; 3295.064 s |
|
||||
| Tiny IHP130 PR | `regress-tiny-ihp130.{json,log}` | Pass; 2297.373 s |
|
||||
| Mini ICS55 behavioral-only PR | `regress-mini-ics55.{json,log}` | Pass; 3093.379 s; no Mini physical evidence |
|
||||
| P4 Verilator replay | `replay-verilator.{json,log}` | Both selected images once; 357.537 s including build/audit |
|
||||
| P4 Icarus replay | `replay-iverilog.json`, `replay-iverilog.json.log` | Banked image once; 5214.736 s including build/audit |
|
||||
| Matched-image aggregation | `report-result.json`, `report.log`, `report.json` | `measurement_complete`; all banked samples match across simulators |
|
||||
|
||||
The six standalone memory logs report `local_latency_max=3`, with real
|
||||
simultaneous group issues. Those protocol fixtures use a 10 ns verification
|
||||
clock; product replays and timing checks use SAFE24. The banked product replay
|
||||
also observes three-cycle maximum local latency and zero eligible bank-conflict
|
||||
cycles. No physical frequency qualification follows from functional models.
|
||||
|
||||
Commands were run through `scripts/run_flow.py` for retained logs/results:
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
export BUILD_TIMESTAMP=2026-10-10-10-05
|
||||
export JOBS=3
|
||||
make rtl-format-check rtl-style-check-all rtl-readiness-check-all
|
||||
make sw-format-check sw-policy-check sw-host-test
|
||||
ruff check .
|
||||
git diff --check
|
||||
python3 -m pytest -q --basetemp=build/ics55-tiny-2026-10-10-10-05-b4aa59f3e5d9/meta/tiny-r2-p4/tests-full
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc MINI --pdk ICS55 --behavioral-only --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130
|
||||
JAVA_TOOL_OPTIONS=-Dsbt.server.forcestart=true python3 scripts/regress.py \
|
||||
--root . --suite pr --soc MINI --pdk ICS55 --behavioral-only
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 SIMU=VERILATOR SOC_SIM_TIME=21600 \
|
||||
TINY_P4_REFERENCE=build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/report.json \
|
||||
TINY_P4_CASES=perf-o2-plain-flat,perf-o2-plain-banked tiny-r2-p4-replay
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 SIMU=IVERILOG SOC_SIM_TIME=21600 \
|
||||
TINY_P4_REFERENCE=build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/report.json \
|
||||
TINY_P4_CASES=perf-o2-plain-banked tiny-r2-p4-replay
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 tiny-r2-p4-report
|
||||
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
make CONFIG=configs/ci/ihp130-tiny.mk SOC=TINY PDK=IHP130 APP=ci_smoke SYNTH=YOSYS STA=OPENSTA metrics
|
||||
```
|
||||
|
||||
Tiny PR and nightly expand to the same commands; nightly was not duplicated.
|
||||
Each simulation requires command success, its configured terminal marker and
|
||||
no forbidden-error marker. All selected ordinary targets require SIM_TEST_PASS,
|
||||
including Tiny netlist boot. UART text alone is insufficient. Development
|
||||
attempts are not counted as extra qualifying cold starts.
|
||||
|
||||
## Measurements and remaining qualification
|
||||
|
||||
Raw cycles below compare each immutable binary with its own P3 baseline.
|
||||
The report also retains retired instructions, CPI inputs, empty calibration,
|
||||
local waits, macro issues/conflicts and external traffic accounting.
|
||||
|
||||
| Workload | Flat P3 → P4 cycles | Banked P3 → P4 cycles |
|
||||
| --- | ---: | ---: |
|
||||
| CPU | 73951 → 73911 | 73954 → 73914 |
|
||||
| CPU copy | 127157 → 102568 | 114875 → 86214 |
|
||||
| DMA burst 1 | 64577 → 91306 | 64583 → 89365 |
|
||||
| DMA burst 16 | 16520 → 36713 | 16523 → 36489 |
|
||||
| CPU/DMA contention | 310368 → 303493 | 310383 → 299633 |
|
||||
| TCD contention | 310665 → 303702 | 310683 → 299645 |
|
||||
| Chunk 256 | 373812 → 377705 | 374016 → 376970 |
|
||||
|
||||
CPU-copy cycles decrease by about 19%/25%, while isolated burst-16 DMA takes
|
||||
about 2.2 times the baseline cycles. The current external frontend processes
|
||||
issue, completion and bus response separately for each beat; preserving local
|
||||
response isolation costs streaming throughput. This regression is retained for
|
||||
review, not hidden by the CPU-copy result or a changed compiler/layout. P5's
|
||||
external target concurrency alone does not remove these per-beat waits. No
|
||||
fixed speedup was an acceptance gate, but the tradeoff needs explicit assessment
|
||||
before phase acceptance or a throughput claim.
|
||||
|
||||
Actual synthesis/STA variants are
|
||||
`build/ics55-tiny-2026-10-10-10-05-42d5beccb726/` and
|
||||
`build/ihp130-tiny-2026-10-10-10-05-bff91e3529ba/`.
|
||||
Both emit `TINY_R2_P4_BINDING_PASS` and pass netlist boot. Their raw reports are
|
||||
`sta/opensta/timing_metrics.rpt`, `p4-clock-bindings.rpt`, `retrosoc_sta.log` and
|
||||
`meta/metrics.json`.
|
||||
|
||||
| PDK | Cells | Reported library area | Max WNS / TNS (ns) | Min WNS / TNS (ns) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| ICS55 | 206311 | 1803352.980799 | -40.55 / -518700.31 | -0.02 / -11.85 |
|
||||
| IHP130 | 216216 | 9218095.882797 | -97.46 / -1626503.88 | -0.17 / -142.67 |
|
||||
|
||||
Timing is not closed. Library area is not placed/routed die area. Lint baseline
|
||||
comparisons remain non-blocking observations: Tiny ICS55 466 new signatures,
|
||||
Tiny IHP130 410 new, Mini ICS55 1537 new / 118 resolved, all with zero increased.
|
||||
Compared with the preceding P3 lint runs, newly observed signatures are intentional
|
||||
empty named output connections: Tiny's unused master IDs, exclusive/power/fence
|
||||
outputs, plus Mini's ignored `reset_pending_o`. Tiny is cacheless with committed
|
||||
stores, no A/SBA and no Xh3Power, so these outputs do not add interfaces or clock
|
||||
gating. Baselines and metric policy were not edited. The logs retain the known
|
||||
generated-file clock skew and successful ABC Liberty fallback observations.
|
||||
|
||||
The P3 eight-configuration matrix and three-cold-start campaign were not rerun.
|
||||
No place/route, extracted/PVT/CDC/RDC signoff, high-rate qualification, new PDK
|
||||
rollout or PDF build/visual check was performed. Publication snapshot enforcement
|
||||
remains enabled; the reviewed PDF source revision was not advanced. Mini
|
||||
DMA-to-WS2812 stays unsupported under option A, and product DMA/IRQ budgets
|
||||
remain for a supported integration. P5 and later features are not implemented.
|
||||
@@ -3,6 +3,9 @@
|
||||
This record covers the two P1 findings approved for follow-up on
|
||||
`bab01352f8f7c80e39546b04e3ed37a3d927f475` plus the existing P3 worktree.
|
||||
It does not approve Mini fabric enablement or advance TINY-R2-P4.
|
||||
Earlier sections retain their original development status and attribution;
|
||||
the source-bound campaign below records completed validation on `3e46cc8`.
|
||||
The final section separately records the subsequent two HAL race fixes.
|
||||
|
||||
## Retained Tiny Icarus finding: closed
|
||||
|
||||
@@ -182,6 +185,10 @@ STA observations qualify a new physical operating point.
|
||||
|
||||
## Compiler-matrix execution corrections (2026-10-09)
|
||||
|
||||
The intermediate snapshots below are historical. The final source-bound results
|
||||
later in this record supersede their in-progress status without relabeling any
|
||||
failed attempt or earlier artifact.
|
||||
|
||||
The initial flat-image collector could not read `_stack_point` from its symbol
|
||||
listing. Flat placement now falls back to the retained linker map's explicit
|
||||
`PROVIDE (_stack_point = .)` value; the exact SRAM endpoint and 4 KiB stack
|
||||
@@ -286,3 +293,280 @@ the selected target's successful simulation checks. This behavioral-only run
|
||||
provides no Mini synthesis, netlist, STA or physical evidence. Mini lint baseline
|
||||
differences remain non-blocking observations, separately retained in the
|
||||
`56f28cd9230c` variant's `meta/rtl-lint-warnings.json`.
|
||||
|
||||
## Final source-bound P3 matrix (2026-10-10)
|
||||
|
||||
After the external style commit and the publication/configuration corrections
|
||||
settled, the final campaign was run against commit
|
||||
`3e46cc80e2d2243233d284b7cd9583714b0773bb`, source digest
|
||||
`a7fc5112cd6f20df956243c4d081a6a31ede6192cd270e3c13340557b0e58776`.
|
||||
Its master record is
|
||||
`build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/matrix/attempt-3jy5g5vo/record.json`;
|
||||
the final report is in the same root at `meta/tiny-r2-p3/report.json`.
|
||||
|
||||
All eight cases pass image collection, normal Tiny acceptance and three cold
|
||||
Verilator runs. The selected native Icarus cases also pass three cold runs:
|
||||
|
||||
- `compat-os-flat`: 7464.762, 7891.159 and 7428.430 seconds;
|
||||
- `perf-o2-lto-flat`: 5841.742, 5890.497 and 6149.375 seconds;
|
||||
- `perf-o2-plain-banked`: 5951.447, 6345.716 and 5964.039 seconds.
|
||||
|
||||
The collector validates Tiny `TEST_STATUS`/`SIM_TEST_PASS`, forbidden markers,
|
||||
matched retained image/model/tool artifacts, source digests, three repetitions,
|
||||
and cross-simulator sample identity. `report.json` remains
|
||||
`measurement_complete`; the ledger's human phase gate is still required.
|
||||
|
||||
The earlier 09-25, 15-10 and 16-45 campaigns remain historical: source changes
|
||||
during execution included the `352b200` style commit, the configuration/publication
|
||||
repairs, and the performance profile's trailing-newline change. Their raw passing
|
||||
samples and provenance failures are retained and are not relabeled as final
|
||||
evidence. The final campaign uses the complete committed corrections in `3e46cc8`.
|
||||
|
||||
### Current validation and commands
|
||||
|
||||
The tested primary platform is TINY/ICS55, external SAFE24 with HAVE_PLL=YES
|
||||
but the PLL parked off. CPU and the existing 128 KiB main SRAM remain at SYS24.
|
||||
The IHP130 compatibility profile keeps no PLL. Dependencies, warning baselines,
|
||||
metrics policy, hardware integration and the frozen specification blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4` are unchanged by this validation.
|
||||
|
||||
After activating `.cache/retrosoc/development/tiny-r2-p1/activate.sh`, the matrix
|
||||
and final report commands were:
|
||||
|
||||
```sh
|
||||
make CONFIG=configs/benchmark/ics55-tiny-performance.mk SOC=TINY PDK=ICS55 \
|
||||
BUILD_TIMESTAMP=2026-10-09-17-10 SOC_SIM_TIME=21600 JOBS=3 \
|
||||
TINY_P3_RESUME=NO tiny-r2-p3-matrix
|
||||
make CONFIG=configs/benchmark/ics55-tiny-performance.mk SOC=TINY PDK=ICS55 \
|
||||
BUILD_TIMESTAMP=2026-10-09-17-10 tiny-r2-p3-report
|
||||
```
|
||||
|
||||
The current full Pytest run reports **1629 passed, 1 skipped** in 4200.10 seconds.
|
||||
The one skipped PDF inspection test requires `pypdf`, absent from this environment;
|
||||
it is not a hardware or simulation pass. Its command, complete log and result are
|
||||
in the matrix root under `meta/tiny-r2-p3/quality/pytest.{log,json}`. The previous
|
||||
4 failures and 94 fixture errors remain in their old logs; they are resolved by
|
||||
the configuration declaration and publication/source-fixture corrections in
|
||||
`3e46cc8`. The focused correction check also passed 149 tests with the same one
|
||||
PDF skip. No PDF or publication source revision was advanced by these checks.
|
||||
|
||||
`ruff check .`, dependency-lock validation and `git diff --check` pass. The
|
||||
current C format/policy/host and RTL format/style/readiness checks pass; their
|
||||
exact Make command and outputs are retained under
|
||||
`meta/tiny-r2-p3/quality/policy.{log,json}`. These are the repository's mechanical
|
||||
quality checks, not complete MISRA certification; no new deviation is recorded.
|
||||
|
||||
Regression dry-runs selected TINY explicitly for both PDKs and MINI with
|
||||
`--behavioral-only`. Tiny nightly resolves to the same commands as PR, so it was
|
||||
not executed a second time. The final executions were:
|
||||
|
||||
```sh
|
||||
BUILD_TIMESTAMP=2026-10-09-19-55 python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55
|
||||
BUILD_TIMESTAMP=2026-10-09-19-56 python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130
|
||||
JAVA_TOOL_OPTIONS=-Dsbt.server.forcestart=true BUILD_TIMESTAMP=2026-10-09-19-57 \
|
||||
python3 scripts/regress.py --root . --suite pr --soc MINI --pdk ICS55 --behavioral-only
|
||||
```
|
||||
|
||||
All three exit zero. Current evidence roots and results are:
|
||||
|
||||
| Scope | Evidence root below `build/` | Result |
|
||||
| --- | --- | --- |
|
||||
| Tiny ICS55 PR | `ics55-tiny-2026-10-09-19-55-42d5beccb726/` | `meta/tiny-r2-p3/regress-ics55.{log,json}`; behavioral/JTAG, netlist boot, synthesis and STA commands pass |
|
||||
| Tiny IHP130 PR | `ihp130-tiny-2026-10-09-19-56-bff91e3529ba/` | `meta/tiny-r2-p3/regress-ihp130.{log,json}`; same target-specific gates pass |
|
||||
| Mini ICS55 behavioral-only | `ics55-2026-10-09-19-57-d1cacf6d3b62/` | `meta/tiny-r2-p3/regress-mini.{log,json}`; SDRAM Verilator and Icarus assembly boot pass |
|
||||
|
||||
Each Tiny PR's HAVE_SVA=YES Verilator acceptance has its separate configuration
|
||||
variant, identified in the retained command/log. Mini's SDRAM run uses
|
||||
`dc24d22ad53d` and assembly boot uses `ec9e1f2e9c2c` at the same 19-57 timestamp.
|
||||
Mini behavioral-only supplies no synthesis, netlist, STA or physical evidence.
|
||||
|
||||
The additional IHP130 performance/banked normal-firmware check also passes:
|
||||
|
||||
```sh
|
||||
make CONFIG=configs/ci/ihp130-tiny.mk SOC=TINY PDK=IHP130 \
|
||||
BUILD_TIMESTAMP=2026-10-10-00-13 SW_ISA_PROFILE=TINY_PERF SW_OPT=O2 SW_LTO=NO \
|
||||
LINK_TYPE=ld2_tiny_banked SIMU=VERILATOR firmware sim
|
||||
```
|
||||
|
||||
Its root is `build/ihp130-tiny-2026-10-10-00-13-8648aa4845d9/`, with the exact
|
||||
command/result at `meta/tiny-r2-p3/performance-banked.{log,json}` and strict Tiny
|
||||
simulation check at `sim/verilator/result-sim-check.json`. This is normal
|
||||
firmware compatibility; it is not an additional IHP130 compiler measurement matrix.
|
||||
|
||||
The ICS55 platform auditor captured inputs before this execution and successfully
|
||||
produced `meta/tiny-ics55-p1/report.json` in the actual APP=ci_smoke variant. This
|
||||
reuses the platform audit under P3; its original phase label is unchanged. Metrics
|
||||
were explicitly collected in each actual synthesis/STA variant rather than the
|
||||
regression runner's final default-bringup observation directory:
|
||||
|
||||
| TINY PDK | Cells | Reported library area | Max WNS (ns) | Max TNS (ns) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| ICS55 | 197677 | 1786686.260799 | -41.14 | -508669.53 |
|
||||
| IHP130 | 208547 | 9109320.296998 | -94.28 | -1594880.00 |
|
||||
|
||||
Both min WNS/TNS values are zero in these smoke reports. Full reports are at
|
||||
`sta/opensta/timing_metrics.rpt` and `meta/metrics.json` within the corresponding
|
||||
APP=ci_smoke roots. Library area is not placed/routed die area; negative margins
|
||||
remain unclosed. No 96/192/240 MHz operation, routed/PVT signoff or physical
|
||||
qualification is claimed, and no half-rate main-SRAM fallback is introduced.
|
||||
|
||||
Lint comparisons remain non-blocking observations: ICS55 Tiny has 459 new
|
||||
signatures relative to its baseline, IHP130 Tiny 403, and Mini ICS55 1536 new /
|
||||
118 resolved; all three have zero increased signatures. Counts are not attribution
|
||||
of every warning to P3. The reports are in each timestamp's lint variant
|
||||
(`303f95040df3`, `2dc2e5c747e5`, and `56f28cd9230c` respectively), under
|
||||
`meta/rtl-lint-warnings.json`. Baselines were not edited.
|
||||
|
||||
### Software measurements and remaining boundaries
|
||||
|
||||
Each row below uses the retained P3 workload (1024 words, four jobs, 4096 CPU
|
||||
iterations, seed `0x12345678`). Cycle counts are raw measured windows; the report
|
||||
also retains the separate empty-window calibration, retired instructions, bus
|
||||
observations and CPI. These are different compiler/layout binaries, not a
|
||||
matched-binary architectural speedup claim.
|
||||
|
||||
| Case | BIN bytes | CPU cycles | Copy cycles | Burst-16 DMA cycles | Chunk-256 cycles | Observed stack bytes |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||
| compat-os-flat | 11132 | 98682 | 164096 | 18881 | 511389 | 692 |
|
||||
| perf-o2-plain-flat | 10148 | 73951 | 127157 | 16520 | 373812 | 648 |
|
||||
| perf-o2-lto-flat | 8592 | 73974 | 127180 | 13980 | 339167 | 552 |
|
||||
| perf-o3-plain-flat | 10404 | 73951 | 127157 | 16058 | 372690 | 628 |
|
||||
| perf-o3-lto-flat | 9872 | 73974 | 127180 | 13980 | 339167 | 564 |
|
||||
| perf-os-plain-flat | 8000 | 74064 | 139487 | 18421 | 394248 | 692 |
|
||||
| perf-os-lto-flat | 6360 | 74064 | 139484 | 14169 | 343769 | 584 |
|
||||
| perf-o2-plain-banked | 10184 | 73954 | 114875 | 16523 | 374016 | 648 |
|
||||
|
||||
Compare compatible Os with performance Os to hold optimization/layout fixed;
|
||||
compare performance O2 with/without LTO to isolate that selection; compare the
|
||||
two O2/no-LTO rows for placement. BIN bytes exclude BSS, and observed stack use
|
||||
does not prove a static upper bound. Each image reserves at least 4096 stack
|
||||
bytes. Bank conflicts remain unavailable because P4 hardware is not implemented.
|
||||
The original P1 binaries and their historical phase/source identities are retained.
|
||||
|
||||
Current Mini PIO compatibility is additionally retained at
|
||||
`build/ics55-2026-10-09-20-00-d0c568d0142e/meta/tiny-r2-p3/pio-retry/evidence.json`.
|
||||
The initial default 180-second attempt emits SIM_TEST_TIMEOUT despite emulator
|
||||
exit zero, and fails the simulation checker. A retry of the identical model and
|
||||
BIN with `--fast-flash -t 1800` passes in 323.930 seconds, including 4/16/33/65-word
|
||||
frames, IRQ count 5, exact waveform/reset-low checks, underflow/abort recovery,
|
||||
and observer totals `frames=6 completed=4 underflows=1 aborts=2 dma_starts=0`.
|
||||
The evidence records the before/after model and BIN hashes, command, manifest,
|
||||
compile/run logs and a post-build recheck of 487 compiled input sizes/mtimes.
|
||||
It is explicitly a post-build audit; neither the failed timeout nor the original
|
||||
unsupported Mini DMA attempt is relabeled as a passing run.
|
||||
|
||||
Product-integrated WS2812 DMA/IRQ service budgets remain deferred under approved
|
||||
option A to an actual supported route, including Tiny R2-P6. Full-product,
|
||||
physical, silicon and publication-PDF qualification remain outside these results.
|
||||
Human review and acceptance of TINY-R2-P3 are required before authorizing any
|
||||
R2-P4 implementation; this execution does not automatically advance a phase.
|
||||
|
||||
## Subsequent P1 HAL race fixes (2026-10-10)
|
||||
|
||||
This approved follow-up starts from `3e46cc80e2d2243233d284b7cd9583714b0773bb`
|
||||
and preserves the preceding uncommitted documentation/evidence updates. The
|
||||
specification remains blob `7e19de49d49efaafacccfa85671e314d53dd15a4`.
|
||||
Only `crt/src/hal/dma.c`, `crt/src/hal/ws2812.c` and
|
||||
`tests/c/test_runtime.c` change executable/test source. No public interface,
|
||||
register, RTL, profile, dependency, warning baseline or metric policy changes.
|
||||
|
||||
- WS2812: completing between INTR_STATE and STATUS reads no longer produces a
|
||||
false I/O error. Idle without an observed sticky DONE retains ownership and
|
||||
returns to the caller; the next bounded service checks error, abort, deadline
|
||||
and completion again. No refill is admitted to an idle core. DMA response
|
||||
draining and source-buffer lifetime rules are unchanged.
|
||||
- DMA: one outer interrupt save/restore spans legacy TCD configuration,
|
||||
descriptor publication and START, including ownership rejection. Nested HAL
|
||||
helpers preserve the saved mask; the blocking completion wait is outside this
|
||||
critical section. Test-only IRQ hooks model a pending ISR at mask restoration
|
||||
and do not appear in target builds.
|
||||
- Deterministic production-HAL host tests cover an ISR trying to lease the
|
||||
channel during TCD publication, rejection without modifying an existing lease,
|
||||
an initially masked caller, completion between WS2812 register reads, delayed
|
||||
sticky DONE, genuine error/abort and expiry while idle. Existing final-B drain,
|
||||
timeout ownership and 16-word FIFO admission tests remain enabled.
|
||||
|
||||
New evidence is rooted at
|
||||
`build/ics55-tiny-2026-10-10-09-00-b4aa59f3e5d9/meta/tiny-r2-p3-races/`.
|
||||
The timestamp is a fixed build label; each structured result records actual UTC
|
||||
start/end times. `source.json` records the base revision, dirty state, locked
|
||||
tool identities, input hashes, source archive and worktree patch. Its combined
|
||||
ICS55/IHP130 source/test/spec digest is
|
||||
`dfa171fc1adbdfc5c7c9d31ef4ac7ba1a66710caac0fb13b869ddac89186b2f7`.
|
||||
This digest's input set differs from the earlier compiler-matrix input set.
|
||||
|
||||
Before fixes, `host-red.{log,json}` records host test exit 10 (TCD race).
|
||||
After the TCD fix alone, `host-ws-red.{log,json}` records exit 11 (WS2812 race).
|
||||
Both fail the enclosing Make command. `host-green.{log,json}` passes after both
|
||||
fixes; `policy.{log,json}` additionally covers the final error/abort/deadline and
|
||||
interrupt-mask cases, C formatting and policy checks. `focused.{log,json}` has
|
||||
156 passing tests, including P3, Tiny baseline, DMA/register parity, WS2812 RTL
|
||||
and publication API behavior. No new MISRA deviation is introduced. These are
|
||||
partial project checks, not complete MISRA certification.
|
||||
|
||||
Commands run with the existing locked environment:
|
||||
|
||||
```sh
|
||||
source .cache/retrosoc/development/tiny-r2-p1/activate.sh
|
||||
make sw-format-check sw-policy-check sw-host-test
|
||||
python3 -m pytest -q tests/test_tiny_r2_p3.py tests/test_tiny.py \
|
||||
tests/test_tiny_r2_baseline.py tests/test_dma.py \
|
||||
tests/test_dma_register_parity.py tests/test_ws2812.py \
|
||||
tests/test_publication_api_bundle.py
|
||||
ruff check .
|
||||
git diff --check
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite nightly --soc TINY --pdk ICS55 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
|
||||
python3 scripts/regress.py --root . --suite pr --soc MINI --pdk ICS55 --behavioral-only --dry-run
|
||||
BUILD_TIMESTAMP=2026-10-10-09-00 JOBS=3 JAVA_TOOL_OPTIONS=-Dsbt.server.forcestart=true \
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55
|
||||
BUILD_TIMESTAMP=2026-10-10-09-00 JOBS=3 JAVA_TOOL_OPTIONS=-Dsbt.server.forcestart=true \
|
||||
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130
|
||||
BUILD_TIMESTAMP=2026-10-10-09-00 JOBS=3 JAVA_TOOL_OPTIONS=-Dsbt.server.forcestart=true \
|
||||
python3 scripts/regress.py --root . --suite pr --soc MINI --pdk ICS55 --behavioral-only
|
||||
JAVA_TOOL_OPTIONS=-Dsbt.server.forcestart=true make CONFIG=configs/ci/ics55.mk \
|
||||
SOC=MINI PDK=ICS55 APP=ci_smoke WS2812_P3_ACCEPTANCE=YES HAVE_CSR=YES \
|
||||
LINK_TYPE=ld2_all_sram SIMU=VERILATOR VERILATOR_SIM_ARGS=--fast-flash \
|
||||
SOC_SIM_TIME=3600 BUILD_TIMESTAMP=2026-10-10-09-00 JOBS=3 firmware sim
|
||||
```
|
||||
|
||||
Regression dry-runs passed; Tiny PR and nightly select identical commands, so
|
||||
the long run is not duplicated. All three regression executions passed once;
|
||||
their exact commands and verdicts are retained as
|
||||
`regress-{tiny-ics55,tiny-ihp130,mini-ics55}.{log,json}` in the new evidence root.
|
||||
Durations are 3210.491 seconds (Tiny ICS55), 2205.505 seconds (Tiny IHP130),
|
||||
and 3170.591 seconds (Mini ICS55 behavioral-only). Mini PIO passes once in
|
||||
423.766 seconds including build, with 4/16/33/65-word frames, five IRQs and
|
||||
observer totals `frames=6 completed=4 underflows=1 aborts=2 dma_starts=0`.
|
||||
Its variant is `build/ics55-2026-10-10-09-00-d0c568d0142e/`.
|
||||
|
||||
`audit.py` and `evidence.json` retain the final artifact audit: all 1287 captured
|
||||
source/test/spec inputs are unchanged, 487 Mini PIO compiled inputs retain their
|
||||
recorded sizes/mtimes, and the firmware/model/log/result hashes are recorded.
|
||||
The Mini model audit is explicitly post-build. Eight ordinary regression
|
||||
simulations are independently checked against their executable success marker,
|
||||
command exit and forbidden-error rules. All selected targets, including the
|
||||
current Mini assembly fixture, require `SIM_TEST_PASS`; UART output is not used
|
||||
to infer success. This evidence is in addition to the separate PIO audit.
|
||||
|
||||
Current Tiny synthesis/netlist/STA results are in
|
||||
`build/ics55-tiny-2026-10-10-09-00-42d5beccb726/` and
|
||||
`build/ihp130-tiny-2026-10-10-09-00-bff91e3529ba/`. Both netlist checks pass;
|
||||
STA command success does not mean timing closure. Observed max WNS/TNS remain
|
||||
-41.14 ns / -508669.53 ns (ICS55) and -94.28 ns / -1594880.00 ns (IHP130),
|
||||
with min WNS/TNS zero. Raw reports are `sta/opensta/timing_metrics.rpt`.
|
||||
Lint baseline comparisons still fail as non-blocking regression observations:
|
||||
459 new signatures for ICS55 Tiny, 403 for IHP130 Tiny, and 1536 new / 118
|
||||
resolved for Mini, with zero increased signatures. No baseline was changed.
|
||||
Build logs also retain a roughly four-second generated-file clock-skew warning;
|
||||
these were fresh variant builds, and the input audit passed.
|
||||
|
||||
The old compiler/layout matrix, full Pytest and earlier timing observations stay
|
||||
bound to `3e46cc8`; they are not reattributed to this follow-up. The compiler
|
||||
matrix and full Pytest are not rerun for these isolated C changes (no build or
|
||||
Python implementation changes). Product-integrated WS2812 DMA/IRQ budgets remain
|
||||
deferred under option A; no Mini DMA-to-MMIO route is added. Human P3 acceptance
|
||||
and separate approval are still required before R2-P4. Per the maintainer's
|
||||
instruction, long checks default to a single execution; additional repetitions
|
||||
need a concrete failure/inconsistency or an explicit frozen acceptance rule.
|
||||
@@ -0,0 +1,253 @@
|
||||
# Tiny R2-P6 shared integration
|
||||
|
||||
Implementation in progress from `b3b30a72cd6ef5340c28e5044c96cd13258ec5a6`,
|
||||
against specification blob `7e19de49d49efaafacccfa85671e314d53dd15a4`.
|
||||
The maintainer approved the single-phase P6 preflight. No phase acceptance,
|
||||
new operating-frequency claim, commit or publication promotion follows.
|
||||
|
||||
Default `configs/ci/ics55-tiny.mk` remains SAFE24 with its PLL parked off;
|
||||
`configs/ci/ihp130-tiny.mk` remains no-PLL compatibility. CPU and all 32 main
|
||||
SRAM macros share SYS. Crypto adds its six private 4 KiB macros on the current
|
||||
SAFE24 PCLK alias, without reducing the 128 KiB main aperture.
|
||||
|
||||
## Product boundary
|
||||
|
||||
The eight-channel DMA enables requests 0-8 and 12/13 (`0x31ff`). I2C1 requests
|
||||
9/10, DVP11 and future requests stay unsupported. Default owners are UART0=0,
|
||||
I2C0=1, camera reservation/explicit memory borrowing=2, serialized bulk=3,
|
||||
Crypto=4/5 and audio=6/7. The application lease on channel 3 persists across
|
||||
all WS2812 refill batches; CRC and XPI must acquire it only after release.
|
||||
SPI16/17 remain outside the existing V2.0 selector ABI and are rejected by
|
||||
the SDK. This does not claim hardware rejection of arbitrary raw extended
|
||||
selector writes: the common DMA specification explicitly records their legacy
|
||||
truncation and requires V2.2 identity/capability guards before SPI integration.
|
||||
|
||||
The 20 independent APB branches occupy fabric targets 5-24. SRAM remains
|
||||
0-3, XPI memory 4, and decode/protocol errors are 25/26. The original three
|
||||
external owners remain; owner 2 is now the actual SDIO private DMA producer.
|
||||
P5 response retention, write drain, fault routing and ownership are preserved.
|
||||
The 21 system reset leaves exclude the independently released AUDIO reset;
|
||||
neither an absent audio reference nor Crypto initialization holds CPU reset.
|
||||
|
||||
Gen1 default GPIO routes are SDIO0-5, UART8/9, I2C10/11, audio12-17,
|
||||
PWM18-25 (plus its frozen ALT1 outputs), WS26 and XPI chip selects29-31.
|
||||
Unfrozen UART/I2C alternate inputs, camera, SPI and CLKOUT remain inactive.
|
||||
The historical ASIC wrapper still has legacy dedicated UART/XPI-CS ports and
|
||||
its old power-pad inventory. It is not a QFN64 binding. This explicitly
|
||||
approved compatibility boundary leaves the complete package/power wrapper
|
||||
to final physical implementation, without changing the frozen package table.
|
||||
|
||||
## Shared correctness and software
|
||||
|
||||
Tiny's shared DMA validator now accepts integrated streams and eight channels.
|
||||
Known absent I2C1/SDIO1 and UART flow-control operations fail before MMIO.
|
||||
SD/SDIO enumeration caps a protocol clock request at half the actual input
|
||||
frequency; the existing low-level clock calculator still rejects invalid
|
||||
requests. The bounded SDSC CSD multiplier uses a 32-bit shift factor inside
|
||||
the unchanged 64-bit capacity calculation, avoiding an absent RV32 runtime
|
||||
helper without replacing the locked GNU toolchain.
|
||||
The SD Memory RCA extraction uses raw R6 frame bits 39:24; the preceding
|
||||
31:16 selection incorrectly shifted the assigned card address by eight bits.
|
||||
|
||||
The independent P6 I2S payload fixture reproduced an existing receive-bit
|
||||
assembly defect in both simulators. Completion now follows capture of the
|
||||
current sample's LSB at the LRCK boundary. Both widths preserve the existing
|
||||
register ABI, FIFO/CDC topology and master-only integration. Shared Mini/APU
|
||||
checks remain required; this is not an I2S slave extension.
|
||||
|
||||
Adding partial external GPIO drivers exposed a locked-Verilator simulation
|
||||
limitation: a packed `tri1` bus loses pulls on its otherwise undriven bits.
|
||||
The original I2C test consequently saw released SCL/SDA low and timed out.
|
||||
A minimal reproduction fails in Verilator and passes in Icarus; explicit
|
||||
independent scalar board nets retain both weak pulls and driven readback in
|
||||
both tools. Tiny's generated testbench bindings use those scalar nets and an
|
||||
observation-only packed view. ASIC ports, pad cells, power counts and I2C RTL
|
||||
are unchanged by this verification repair.
|
||||
|
||||
The Tiny `HAVE_SVA=YES` flow now also emits `+define+HAVE_SVA`, which the
|
||||
owned P4/P5 assertions use. Previously it only omitted the Common
|
||||
`SV_ASSRT_DISABLE` define; focused fixtures explicitly enabled the owned
|
||||
assertions but ordinary firmware flows did not. Mini flag behavior is unchanged.
|
||||
|
||||
The first full integration reached Crypto but timed out before audio completion.
|
||||
A smaller actual-SoC diagnostic isolated an I2S status load fault: Tiny's
|
||||
AXI-to-APB bridge retained the preceding write strobes on reads. Read PSTRB is
|
||||
now zero as required by APB4, while writes retain their byte lanes. A directed
|
||||
write/read sequence checks full/partial writes with a strict receiver.
|
||||
The Tiny firmware limits exception skipping to its explicit CPU probes;
|
||||
unexpected later load/store faults fail immediately instead of being masked.
|
||||
|
||||
Audio shutdown keeps the consumer running while aborting/draining its leased
|
||||
TX DMA session. A held stream beat cannot retire into an already stopped/full
|
||||
audio FIFO. Only after DMA retirement does the acceptance image disable I2S
|
||||
and flush. After a missing-clock flush timeout it polls the outstanding command
|
||||
through clock recovery instead of issuing another protected COMMAND write.
|
||||
|
||||
SDIO's reused card model originally required manual enumeration/data stimulus;
|
||||
its default ACMD41 never reports READY. The command trace confirmed the
|
||||
initialization loop. An opt-in SDHC response profile and the existing explicit
|
||||
data API now support the Tiny board fixture while preserving standalone defaults.
|
||||
The fixture checks wire-command/data-policy agreement and drives only external
|
||||
pins. Card timing/protocol/electrical qualification remains excluded. The native
|
||||
Icarus parser also needs an equivalent explicit enum branch in this model.
|
||||
Tiny Icarus builds now retain separate testbench/header dependencies, including
|
||||
the shared card model and P6 board include. Its serial observer emits measurement
|
||||
records on ordinary runs; TEST_STATUS and strict error checks remain authoritative.
|
||||
|
||||
The 12 MHz command case exposed a running-clock start-bit duplication in the
|
||||
shared SDIO sender. Output admission now waits for its first scheduled launch;
|
||||
the independent pad sampler covers both admission phases. The card sampler
|
||||
retains the complete frame across host OE release, including the pulled-high
|
||||
end bit. This preserves the command/register ABI and does not extend card modes.
|
||||
|
||||
The full four-lane SDIO block exposed a separate transmit pause defect: when
|
||||
memory delayed the next word, a late clock stop corrupted its first bit
|
||||
(`0x57` became `0xD7`) and caused CRC rejection. The shared data engine now
|
||||
requests the pause before that launch; the clock wrapper honors it while
|
||||
draining the current high half-cycle. A full 1024-byte fixture with read-beat
|
||||
gaps checks payload, CRC and descriptor retirement. Its scalar three-state
|
||||
variant also caught card-model assumptions about unused lanes being zero;
|
||||
token and partial-tail checks now account for their pulled-high state.
|
||||
|
||||
The receive roundtrip isolated premature descriptor completion after one
|
||||
64-byte write burst. SDIO private DMA retains ownership until every payload
|
||||
burst retires or an error is reported. A separately reproduced receive stop
|
||||
delay shifted the next word (`0x13579BDE` to `0x26AE37BD`); immediate stop
|
||||
qualification prevents the extra launch. The card's read-CRC sequencer also
|
||||
skipped one bit and is corrected independently. Delayed descriptor/payload
|
||||
tests check full readback, CRC, descriptor retirement and both simulators.
|
||||
These repairs add no masters, channels, descriptor fields or operating modes.
|
||||
|
||||
## Validation and historical publication
|
||||
|
||||
Workloads keep the ordinary Tiny boot, SRAM/DMA tail, trap, interrupt, RTC,
|
||||
I2C NACK, JTAG and watchdog-reset checks. P6 adds real GPIO8/9 UART echo;
|
||||
eight-channel/unsupported-request checks; RNG qualification rejection and IRQ;
|
||||
CRC DMA, empty input and byte tails; Crypto initialization, AES/SHA/public RSA,
|
||||
channels 4/5 and zeroization. Audio uses the fixed 18.432 MHz external reference
|
||||
and 48 kHz master presets, checks 256 stereo frames at both 16 and 24 bits,
|
||||
and drives paced 33/65-word WS frames in each case. Channel 2 concurrently runs
|
||||
bounded 256-byte jobs, then four-descriptor chains; channels 6/7 own audio.
|
||||
The board independently decodes I2S/WS pins, checks FIFO/service bounds and
|
||||
stops AUDIO low/high for recovery tests. SDIO uses 400 kHz enumeration/one-bit
|
||||
PIO and 12 MHz four-bit DMA, transfers 1024 bytes in each DMA direction and
|
||||
512 PIO bytes, overlaps a separate 1024-byte central-DMA job and checks IRQ,
|
||||
CRC-error, timeout and recovery behavior.
|
||||
|
||||
MCYCLE/MINSTRET measure the audio/WS service loop after prefill; elapsed CLINT
|
||||
time also includes its bounded preparation. The independent AXI observers count
|
||||
handshakes over the complete firmware run, including boot/control accesses;
|
||||
they are not payload-only bandwidth measurements. Write counts mean accepted
|
||||
strobes, not rollback guarantees. Descriptor fetch bytes, per-owner AR/AW/W/R/B
|
||||
backpressure, WS service gaps and actual SDIO/DMA overlap with CPU progress
|
||||
remain explicit. `scripts/tiny_r2_p6.py` retains ELF/hex/bin/map, linker/generated
|
||||
software inputs, simulator binaries/filelists, manifests, logs and their hashes.
|
||||
Both simulators on both PDKs must have successful commands, Tiny's terminal
|
||||
`SIM_TEST_PASS`, all workload/independent-observer records and no forbidden
|
||||
error marker. Component diagnostics never satisfy that collector.
|
||||
|
||||
The current Tiny PR and nightly dry-run command matrices are identical for
|
||||
each PDK. After focused/quality checks, execute full Pytest once and one full
|
||||
PR per PDK in independent build directories; these broader gates may run in
|
||||
parallel but must all finish before acceptance. Collect warnings/metrics with explicit `APP=ci_smoke`,
|
||||
`SYNTH=YOSYS`, `STA=OPENSTA` and the same build timestamp. Do not rerun an
|
||||
identical nightly matrix. Shared I2S and SDIO standalone/formal checks plus the
|
||||
affected Mini firmware path remain separate compatibility evidence. Core STA
|
||||
must execute and bind all 38 exact macros; its slack remains observational.
|
||||
The legacy IHP130 LibreLane floorplan generator still places the 32 main macros
|
||||
only. It has not placed/connected the six private Crypto macros or implemented
|
||||
the final QFN64 wrapper. Full-chip APR/PDN/package work remains outside this
|
||||
campaign; neither its old floorplan nor smoke STA establishes P6 physical closure.
|
||||
|
||||
Development artifacts begin at the manually selected `2026-10-12-12-00`
|
||||
build label, with subsequent diagnostic labels recorded in each command.
|
||||
Those labels are not wall-clock measurements; JSON start/end times are.
|
||||
Some diagnostic firmware directories were reused while finding defects and
|
||||
must not be rebound to later binaries. The `11-42` snapshot's Make-format gate
|
||||
failed before long validation. The fresh `2026-10-12-11-50` campaign retains
|
||||
its input snapshot under `build/ics55-tiny-2026-10-12-11-50-2eb98c0e1fae/meta/tiny-r2-p6/`.
|
||||
Failed attempts retain their own verdicts and are not acceptance evidence.
|
||||
|
||||
Both original PR attempts passed complete Verilator/JTAG acceptance and then
|
||||
stopped at native Icarus elaboration: `s_token_lanes` referenced `s_data_bytes`
|
||||
before its declaration. The declaration relocation changes no expression or
|
||||
other model byte. `verification-update.json` retains the second snapshot;
|
||||
the collector checks that exact equivalence and rejects any DUT, firmware,
|
||||
constraint, tool or other model-behavior change. Only the card model and its
|
||||
collector/tests differ. Original Verilator and Mini results retain their
|
||||
original source identity. Native Icarus and the remaining physical smoke stages
|
||||
resume from the failed step; the original failed PR verdicts are not rewritten.
|
||||
Full Pytest retains its original collection, with the equivalent model edit
|
||||
during execution; the updated 48-case P6 suite separately covers the native
|
||||
parser and fail-closed provenance checks. Counts overlap and must not be added.
|
||||
|
||||
The one full Pytest attempt reports 1634 passed, one optional `pypdf` skip,
|
||||
five failures and 60 fixture errors. These reduce to two source-consumer issues:
|
||||
Mini's publication parser counted inactive Tiny enum branches as Mini channel
|
||||
allocations, and the commercial Tiny overlay retained its pre-P6 two-domain
|
||||
allowlist. The parser now selects and checks Mini's actual bulk aliases; no book
|
||||
identity, chapter, PDF or historical evidence changes. The commercial policy
|
||||
and Tcl inventory now include the canonical AUDIO root; no licensed flow or
|
||||
qualified I/O run is implied. `consumer-update.json` binds this separate scope
|
||||
and rejects changes to RTL, firmware, models or smoke constraints.
|
||||
|
||||
Every one of the 65 original failed/error nodes passes in the explicit repair
|
||||
selection. The complete affected publication/commercial suite reports 512 passed
|
||||
and one optional PDF-library skip; 35 selected provenance tests also pass.
|
||||
These counts overlap the full attempt and each other. There is no claimed clean
|
||||
full-suite rerun: unaffected long tests were retained with their original scope.
|
||||
|
||||
### Completed Verilator observations (partial campaign)
|
||||
|
||||
`verilator-observations.json` and `report-functional-before-physical.json` bind
|
||||
the following values to successful command/log artifacts. Each row verifies 256
|
||||
stereo frames and two WS frames, with 64 completed background jobs. These values
|
||||
are functional observations, not phase acceptance or timing closure.
|
||||
|
||||
| PDK | Audio bits | Service-loop cycles | Retired instructions | Elapsed including preparation (us) |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| ICS55 | 16 | 141917 | 41351 | 8044 |
|
||||
| ICS55 | 24 | 138353 | 40283 | 7892 |
|
||||
| IHP130 | 16 | 141917 | 41351 | 8065 |
|
||||
| IHP130 | 24 | 138350 | 40283 | 7903 |
|
||||
|
||||
The independent WS service-gap maxima are 2375/2374 SYS cycles
|
||||
(98.96/98.92 us), below the 4800-cycle budget; FIFO peak occupancy is 15/16.
|
||||
Both runs observe 4124 cycles of actual SDIO/private-DMA versus central-DMA
|
||||
overlap, with 1185 CPU instruction-fetch handshakes in that interval. SDIO's
|
||||
external owner reads 1056 bytes and accepts 1032 write bytes, including its
|
||||
descriptor fetch/writeback. Central-DMA descriptor fetches total 16384 bytes.
|
||||
No cross-architecture speedup or physical rate is inferred from these samples.
|
||||
|
||||
Both complete Icarus runs subsequently pass: ICS55 at 16036387 cycles and
|
||||
IHP130 at 16035743 cycles, with the
|
||||
same workload, WS, contention and bus observations as its Verilator run.
|
||||
Its UART observer leaves a partial human-readable line before the testbench's
|
||||
terminal `SIM_TEST_PASS Tiny cycles=...` record. `collection-update.json`
|
||||
records a collector/test-only correction to accept that exact terminal token
|
||||
without requiring a fresh line; JTAG-only/Mini markers, malformed cycle values
|
||||
and forbidden errors remain rejected. Forty focused collection/provenance
|
||||
checks pass. Raw logs, RTL, firmware, models and constraints are unchanged.
|
||||
|
||||
Both netlist boot checks pass at 30030 cycles. Yosys synthesis and OpenSTA run
|
||||
for both PDKs and report the exact 32 main plus 6 private Crypto macro bindings.
|
||||
Observed top-cell/area values are ICS55 412515/2461020.464702 and IHP130
|
||||
433861/13320370.152627. Setup/hold remain negative: ICS55 WNSmax/WNSmin
|
||||
−84.93/−0.31 ns, IHP130 −165.41/−0.51 ns. These are smoke-flow observations;
|
||||
the frozen phase does not use synthesis slack as an intermediate blocking gate.
|
||||
Warning checks retain new Yosys/Verilator/RTL-lint and IHP130 Icarus signatures
|
||||
as non-promoted observations under the existing policy; no baseline was edited.
|
||||
|
||||
The old Tiny publication remains frozen at its advertised technical revision
|
||||
`9c706ba0ff1da1028c299cfff573010a86dfd7ce`. Tests execute the original
|
||||
publication adapter/test snapshot `2805ea91833a6bede32f3a82df3d17d20eb5ec77`
|
||||
and, separately, the later P5 contract snapshot `b3b30a72cd6ef5340c28e5044c96cd13258ec5a6`.
|
||||
Neither snapshot becomes P6 publication evidence. Current P6 source must be
|
||||
rejected by the historical collector. The reset mutation checks still run
|
||||
against the current target RTL. No frozen chapter, reviewed SHA or old PDF is
|
||||
rewritten; unavailable PDF/media inputs remain a separate publication gap.
|
||||
|
||||
P7 RCU/variable clocks, PWM dependency upgrades, alternate-input ABI, slave
|
||||
audio, PSRAM, DVP and later extensions remain outside this phase. Timing is
|
||||
observational before complete-product qualification; exact macro/clock/source
|
||||
binding and successful functional verdicts remain mandatory.
|
||||
@@ -1,14 +1,486 @@
|
||||
# Tiny MCU Verification Record
|
||||
|
||||
## TINY-R2-P3 implementation in progress (2026-10-08–09)
|
||||
## TINY-R2-P7 source-reset integration contract (2026-10-14)
|
||||
|
||||
The follow-up review identified a missing source-side reset proof, not a
|
||||
reproduced product failure. The AXI bridge does not support arbitrarily
|
||||
resetting an active source while leaving its slave session alive. Flushing
|
||||
the FIFO cannot cancel a request already accepted by that slave. Production
|
||||
Tiny prevents that sequence: DMA local reset requires engine, admission and
|
||||
fabric drain before resetting the source; XPI's SYS source reset is a common
|
||||
system reset that also resets its MEM endpoint. Neither production bridge
|
||||
uses warm clear. These preconditions are part of the integration contract,
|
||||
not a claim of unrestricted unilateral-reset support by the standalone bridge.
|
||||
|
||||
`tests/rtl/tiny_p7_source_reset_tb.sv` uses the production DMA master,
|
||||
admission, CDC, lifecycle controller and reset tree. The test extracts the
|
||||
actual top-level instances, drain/block synchronizers and generated DMA/XPI
|
||||
reset bindings, so a hand-copied reset policy cannot silently replace them.
|
||||
An independent outstanding scoreboard survives local reset and rejects
|
||||
premature reset. The AXI target is a controllable behavioral slave; unrelated
|
||||
CPU/APB/SDIO work and the DMA completion mailbox are idle. This is a focused
|
||||
integration test, not a full-SoC firmware or formal CDC/RDC signoff result.
|
||||
|
||||
The scenarios cover stalled AR/AW, partial W, downstream W backpressure,
|
||||
delayed R/B, source-held R, drain timeout without reset, post-reset reads and
|
||||
writes, and common system reset during an outstanding read. The same binary
|
||||
is reused at SAFE24, XIN48, XIN96, PLL192 and PLL240 domain ratios. They test
|
||||
digital ordering only; the clock generators do not qualify a PLL or PDK rate.
|
||||
A negative run falsifies both idle observations and must trip
|
||||
`P7_SOURCE_RESET_UNDRAINED`; Icarus may return zero for sv2v's lowered fatal,
|
||||
so the forbidden marker and missing PASS still make that simulation invalid.
|
||||
|
||||
Evidence for this correction is retained under
|
||||
`build/ics55-tiny-2026-10-14-06-00-ff4b5cef6eb5/meta/tiny-r2-p7-source-reset/`.
|
||||
The first focused attempt's test-driver failure is retained in `focused-1.log`;
|
||||
it is not a DUT failure or acceptance result. The final `directed.log` and
|
||||
`result-directed.json` record **54 passed in 191.71 seconds**. This includes
|
||||
ten positive source-reset runs (five ratios in each simulator) and two
|
||||
expected-negative broken-drain runs inside the two new Pytest cases.
|
||||
RTL format/style, clock/reset inventory, Ruff, both Tiny PDK PR dry-runs and
|
||||
`git diff --check` pass. The verification-only source comparison is retained
|
||||
in `verification-update.json`: only the two test files differ; 1728 other
|
||||
technical inputs and tool identities match. The design,
|
||||
firmware, configuration, dependencies and physical inputs are unchanged from
|
||||
the `06-00` source snapshot; the new tests do not relabel earlier simulations
|
||||
as new executions. Full Icarus firmware remains deferred to final Tiny
|
||||
qualification. Human P7 acceptance is still required.
|
||||
|
||||
## TINY-R2-P7 response conservation correction (2026-10-14)
|
||||
|
||||
The earlier review recommendation to give abort unconditional priority over
|
||||
source response retirement was incorrect. A cycle with an already exposed
|
||||
normal B/R handshake followed by an abort produced two completions for one
|
||||
request. Four read/write tests reproduced this in Verilator and Icarus. The
|
||||
failed candidate, diagnostics and source archive are retained below
|
||||
`build/ics55-tiny-2026-10-14-04-00-ff4b5cef6eb5/meta/tiny-r2-p7-response/`.
|
||||
The `04-00` synthesis/netlist/STA results belong to that rejected candidate;
|
||||
their successful boot does not close the protocol finding.
|
||||
|
||||
The corrected bridge holds presented responses in source-owned registers.
|
||||
Remote reset cannot revoke VALID or rewrite their payload under backpressure,
|
||||
and a completed source handshake is never followed by a second completion.
|
||||
Only missing read beats receive DECERR, with RLAST at the original burst end;
|
||||
a reset write consumes the remaining W beats before emitting B. Outstanding
|
||||
tracking is one transaction per direction, matching the existing Tiny paths.
|
||||
The payload reset uses the five-edge source link barrier. An unfinished warm
|
||||
clear quarantines the bridge until a real destination reset; a FIFO clear
|
||||
cannot by itself cancel remote slave state or authorize re-use of late replies.
|
||||
Production DMA/XPI clear inputs remain tied low; no new software reset API,
|
||||
autonomous AXI timeout, DMA owner, or later-phase capability is introduced.
|
||||
|
||||
The new tests distinguish completed/held responses from missing responses,
|
||||
cover simultaneous clear and response handshakes, remote reset with READY high,
|
||||
backpressure, partial bursts and late-response quarantine. That campaign's
|
||||
full directed selection passed 52 cases. Earlier 36-case and rejected-
|
||||
candidate passes did not cover these failures and are not proof of the repair.
|
||||
The failed same-cycle candidate and diagnostics remain in the response
|
||||
evidence directory.
|
||||
The final input snapshot is
|
||||
`build/ics55-tiny-2026-10-14-06-00-ff4b5cef6eb5/meta/tiny-r2-p7-response/final/source-final.json`.
|
||||
The `06-00` backend campaign is bound to the final source snapshot and all
|
||||
requested post-fix gates pass. Its variants are
|
||||
`build/ics55-tiny-2026-10-14-06-00-ff4b5cef6eb5/` and
|
||||
`build/ihp130-tiny-2026-10-14-06-00-8232fa11e7f3/`. ICS55
|
||||
synthesis/netlist/STA durations are `2108.388/1655.980/43.594 s`, with WNS
|
||||
max/min `-152.03/-0.31 ns` and TNS max/min `-5622052.50/-44.14`; IHP130
|
||||
durations are `1934.515/578.869/47.109 s`, with WNS max/min
|
||||
`-253.43/-0.49 ns` and TNS max/min `-10035324.00/-153.37`. Netlist boot
|
||||
emitted `SIM_TEST_PASS Tiny netlist boot` for both PDKs. These timing values
|
||||
remain observational and do not qualify closure or an operating point.
|
||||
Full Icarus firmware remains deferred by the maintainer to final Tiny
|
||||
qualification. It is not a current P7 gate; protocol correctness and human
|
||||
phase acceptance remain required.
|
||||
|
||||
## TINY-R2-P7 final verification campaign (2026-10-13)
|
||||
|
||||
The [P7 runbook](tiny-soc-r2-clock-reset.md) records the current implementation,
|
||||
exact profile-specific commands, workload definitions and source snapshot.
|
||||
The integrated design now drives actual SYS/MEM/PCLK consumers, CPU-only WFI
|
||||
gating, local reset barriers, CLKOUT and the single ICS55 PLL backend. It keeps
|
||||
the 32 main SRAM macros at CPU SYS and six private Crypto macros at PCLK.
|
||||
Future target capabilities remain absent. No later phase is authorized here.
|
||||
|
||||
Development validation includes 68 passing Tiny P7/SYSCTRL/P5 directed tests
|
||||
and a later complete 52-case P7 directed pass,
|
||||
plus both simulators' real Hazard3 IRQ/debug wake, clock-pause and retained-debug
|
||||
warm-reset/aborted-command cases. RCU validation now rejects invalid or BUSY
|
||||
staging writes with PSLVERR, and the CLKOUT waveform test exposed and corrected
|
||||
enable/divisor ordering. HAL tests cover invalid, absent, busy, gated-reset and
|
||||
sticky-timeout/error boundaries. These short checks complement the final long
|
||||
flows; they do not replace full firmware or netlist acceptance.
|
||||
|
||||
Source evidence is retained at
|
||||
`build/ics55-tiny-2026-10-13-17-05-f3e42d54c18b/meta/tiny-r2-p7/source.json`.
|
||||
The final command matrix and its retained corrections are listed in the runbook.
|
||||
Default ICS55/IHP130 and external XIN48/96 P7 firmware pass in both simulators.
|
||||
Each profile's cycle count and WFI/DMA/reset observations match across simulators.
|
||||
Both watchdog-corrected full Verilator firmware runs pass the unchanged P6
|
||||
peripheral/wire/AXI collector and JTAG. The two corresponding full Icarus
|
||||
replays were intentionally interrupted with exit 130 after the maintainer
|
||||
requested that this long-running gate move to the final Tiny phase; their
|
||||
partial logs and interrupted result records are retained, but they are not
|
||||
acceptance evidence.
|
||||
Both PDKs pass synthesis, structural macro binding and Tiny netlist boot.
|
||||
Current core STA remains observational and negative, with the coverage limits
|
||||
explicit in the runbook. These are historical campaign results; current phase
|
||||
acceptance requires the response correction above and human review. The full
|
||||
Icarus firmware gate belongs to final Tiny qualification. No high-rate physical operating point is
|
||||
qualified by these functional simulations or SAFE24 core STA.
|
||||
|
||||
## Historical TINY-R2-P7 CDC/reset correction follow-up (2026-10-14)
|
||||
|
||||
This checkpoint predates the response-conservation correction and is
|
||||
superseded by the `06-00` campaign above. It is not current-source acceptance.
|
||||
The P7 review identified two source-bound gaps. The XPI fabric target and bridge source side release with
|
||||
the SYS reset endpoint, while the XPI/MEM side retains its MEM leaf reset. The
|
||||
Tiny AXI CDC bridge synchronizes destination reset loss, invalidates its
|
||||
protected request/response state and blocks new source admissions. Its original
|
||||
single-DECERR completion claim was insufficient for held responses and bursts;
|
||||
the later response-conservation correction supersedes that claim. The existing DMA/XPI
|
||||
instances retain their explicit bridge boundaries and the XPI bridge now uses
|
||||
the split SYS/MEM reset mapping.
|
||||
|
||||
The new `tests/rtl/tiny_axi4_async_bridge_tb.sv` passes under both Verilator
|
||||
and Icarus for normal read response, reset-aborted read/write, DECERR,
|
||||
no-replay and bridge recovery. The complete
|
||||
`PYTHONDONTWRITEBYTECODE=1 python3 -m pytest -q tests/test_tiny_r2_p7.py`
|
||||
selection eventually passed 52 tests after the later corrections; that count
|
||||
does not belong to the `01-20` implementation. `make --silent rtl-format-check rtl-style-check-all`
|
||||
and `git diff --check` pass. An ICS55 default-profile Verilator `comp` also
|
||||
passes; its existing PDK and simulator warnings remain observations. The
|
||||
checkpoint's synthesis, netlist boot and observational STA gates passed for
|
||||
both PDKs. Its historical evidence is retained under
|
||||
`build/ics55-tiny-2026-10-14-01-20-ff4b5cef6eb5/` and
|
||||
`build/ihp130-tiny-2026-10-14-01-20-8232fa11e7f3/`. ICS55 reports WNS
|
||||
max/min `-144.40/-0.31 ns` and TNS max/min `-4859636.50/-45.04`; IHP130
|
||||
reports WNS max/min `-257.81/-0.47 ns` and TNS max/min `-9807803.00/-100.68`.
|
||||
These remain observational negative timing results, not closure or operating
|
||||
point qualification. The long-running full Icarus firmware gate remains
|
||||
intentionally deferred to the final Tiny phase; no physical flow was run.
|
||||
|
||||
## Historical initial P7 checkpoint, superseded (2026-10-13)
|
||||
|
||||
The following incomplete checkpoint belongs to earlier development snapshots.
|
||||
Its unconnected/missing-path statements do not describe the final campaign.
|
||||
|
||||
This checkpoint starts from committed source `43a3c8d453b6d41df3536719ebc6d1f4521bc7cd`,
|
||||
specification blob `7e19de49d49efaafacccfa85671e314d53dd15a4`, Tiny/ICS55
|
||||
profile `configs/ci/ics55-tiny.mk`, and the locked PWM revision
|
||||
`38efaf5e20f084a00148920087c60cadab61839b`. The dependency lock validator
|
||||
passes with digest `263402a34f2e315ca46ef4bf6366aab64935bd8de7abab3e469f513e988b0208`.
|
||||
|
||||
The implementation adds the Tiny-owned RCU register bank and handwritten
|
||||
`rcu.h`/`rcu_regs.h`/`rcu.c` contract, reports SAFE24/domain-rate snapshots,
|
||||
connects committed PCLK/SYS rate reporting to the upgraded PWM and SDIO
|
||||
`CLOCK_ACTUAL` paths, and adds focused APB coverage for identity, capability,
|
||||
profile rejection/commit, status and write-only command behavior. Verilator
|
||||
and Icarus SYSCTRL focused tests pass; ICS55 Verilator and Icarus top-level
|
||||
compilation, Tiny firmware linking, C format/policy/host tests and the SDIO
|
||||
suite pass. Build logs are retained under the generated
|
||||
`build/ics55-tiny-2026-10-13-09-00-f3e42d54c18b/` and
|
||||
`build/ics55-tiny-2026-10-13-10-30-f3e42d54c18b/` roots.
|
||||
|
||||
A Tiny-owned `tiny_clock_reset_subsystem` backend is now source-bound and
|
||||
filelisted. Its SAFE24/no-PLL focused test passes in both simulators and covers
|
||||
five-stage SYS/MEM/PCLK reset release, external-profile handling and rejected
|
||||
PLL requests. A second focused test exercises the behavioral PLL lock-timeout
|
||||
path in both simulators; it does not claim successful macro lock or frequency
|
||||
qualification. The backend is intentionally not advertised or wired into the
|
||||
CPU/fabric yet; its SYSCTRL profile/apply handshake is now connected, while
|
||||
the backend instance is now present in the Tiny top and its SYS output clocks
|
||||
the CPU, fabric, SRAM, AXI interfaces and system reset tree. XPI now crosses
|
||||
from SYS to the backend MEM clock through the Tiny-owned warm-flush AXI bridge.
|
||||
The RCU command checks CPU/fabric/target idle observations and the XPI bridge
|
||||
before accepting a transition. PCLK outputs are still not connected to all
|
||||
peripheral consumers.
|
||||
|
||||
The focused command is
|
||||
`PYTHONDONTWRITEBYTECODE=1 python3 -m pytest -q tests/test_tiny_r2_p7.py`;
|
||||
its four cases passed. Supporting gates were
|
||||
`make --silent rtl-format-check rtl-style-check-all`,
|
||||
`make --silent sw-format-check sw-policy-check sw-host-test`,
|
||||
`PYTHONDONTWRITEBYTECODE=1 python3 -m pytest -q tests/test_script_tools.py -k 'run_flow'`,
|
||||
`ruff check scripts/run_flow.py tests/test_tiny_r2_p7.py`, and
|
||||
`python3 scripts/dependency_lock.py --lock dependencies/dependencies.lock.json`.
|
||||
The current ICS55 top-level compile used
|
||||
`source .cache/retrosoc/development/tiny-r2-p1/activate.sh && CCACHE_DISABLE=1 make --silent CONFIG=configs/ci/ics55-tiny.mk APP=ci_smoke SIMU=VERILATOR HAVE_SVA=YES BUILD_TIMESTAMP=2026-10-13-16-30 comp`
|
||||
and exited zero. These are source/compile/focused checks; none is a strict
|
||||
full firmware terminal verdict or physical qualification.
|
||||
|
||||
The long-run diagnostic also confirmed that the emulator itself exits normally
|
||||
with a Tiny timeout at a bounded cycle count and uses about 26 MiB RSS. The
|
||||
earlier `status=running` records lacked a verified terminal result. The initial
|
||||
diagnosis attributed this to sandbox cleanup without sufficient evidence;
|
||||
that conclusion is withdrawn. Separate tool invocations can have different
|
||||
PID namespaces, so process absence in one does not establish that another
|
||||
command died. `run_flow.py` now records `parent_pid` and `child_pid`
|
||||
in the running result and writes a failed terminal result for unexpected
|
||||
Python exceptions; long runs must remain attached to one polling session.
|
||||
|
||||
This is not phase acceptance. The current RTL now uses the backend SYS clock
|
||||
for the system/fabric path, but does not yet provide the required executable
|
||||
MEM/PCLK clock consumers, full CDC bridges, WFI leaf gating, PLL lock/loss
|
||||
recovery, or target-local five-cycle reset sequences. A full Tiny Verilator firmware
|
||||
run was started but did not produce a terminal `TEST_STATUS`/`SIM_TEST_PASS`
|
||||
verdict and was stopped; no physical, STA or netlist qualification is claimed.
|
||||
The remaining P7 clock/reset implementation and strict terminal regressions
|
||||
require a follow-up correction before human phase approval.
|
||||
|
||||
## TINY-R2-P6 implementation complete, human review pending (2026-10-12)
|
||||
|
||||
The maintainer approved the P6 preflight on
|
||||
`b3b30a72cd6ef5340c28e5044c96cd13258ec5a6`, against unchanged specification blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4`. The
|
||||
[P6 runbook](tiny-soc-r2-shared-integration.md) records eight-channel/shared-IP
|
||||
integration, the explicitly retained historical ASIC wrapper and publication,
|
||||
and the separate source-bound validation scope. Development diagnostics are
|
||||
not final acceptance; no P7 or physical-frequency qualification is implied.
|
||||
|
||||
Initial integration exposed a shared I2S sample-LSB assembly defect and a
|
||||
Verilator packed-tri1 board-model limitation. The runbook records their narrow
|
||||
corrections. Directed SDIO integration additionally exposed command admission,
|
||||
transmit/receive pause and multi-burst descriptor-retirement defects, plus
|
||||
manual card-model gaps; their independent reproductions are recorded there.
|
||||
Both Tiny PDKs have complete Verilator and Icarus functional verdicts and
|
||||
netlist boots. Yosys synthesis and OpenSTA run for both PDKs with the exact
|
||||
32-main plus 6-private-Crypto macro bindings. The final audit is
|
||||
`build/ics55-tiny-2026-10-12-11-50-2eb98c0e1fae/meta/tiny-r2-p6/audit-result-v3.json`;
|
||||
the source-bound evidence is `evidence.json` in the same directory. The
|
||||
functional report retains four simulator records, all workload/AXI/device
|
||||
observations and the Mini compatibility result.
|
||||
|
||||
Observed setup/hold slack remains negative: ICS55 WNSmax/WNSmin −84.93/−0.31 ns
|
||||
and IHP130 −165.41/−0.51 ns. Warning checks report new signatures from the
|
||||
existing policy's observation flows; no baseline or metrics policy was edited.
|
||||
The full Pytest attempt remains recorded as 1634 passed, one optional `pypdf`
|
||||
skip, five failures and 60 fixture errors; all 65 failed/error nodes pass in
|
||||
the explicit repair selection, and the affected consumer suite passes 512 with
|
||||
one optional skip. These overlapping counts are not a clean full-suite rerun.
|
||||
Final human review, complete-product timing closure, package/QFN64 binding and
|
||||
physical signoff remain pending. Earlier P5 results and failed P6 attempts
|
||||
retain their original attribution.
|
||||
|
||||
## TINY-R2-P5 P1 protocol correction; validated, review pending (2026-10-12)
|
||||
|
||||
The maintainer requested correction of the reset write-drain/read-retention
|
||||
failures and publication-binding mismatch. The implementation starts from
|
||||
`4e6ab1a6fb445521703f0bfa412d3a1e8a38cd69`; the specification remains blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4`. The [P5 runbook](tiny-soc-r2-concurrent-fabric.md)
|
||||
describes preserved upstream spill responses, complete read/error bursts,
|
||||
write drain before B, latched downstream cancellation and first-error capture.
|
||||
Profiles remain Tiny/ICS55 SAFE24 with parked PLL and Tiny/IHP130 compatibility.
|
||||
|
||||
Current evidence is isolated under
|
||||
`build/ics55-tiny-2026-10-11-23-35-b4aa59f3e5d9/meta/tiny-r2-p5-p1/`.
|
||||
The older `09-30` campaign failed overall: 1669 Pytest passes, one skip,
|
||||
two failures and ten errors (publication), plus independent R stability and
|
||||
W-before-B violations. Its passing ordinary regressions, PPA and replay are
|
||||
historical observations, not acceptance of the repair.
|
||||
|
||||
Final focused validation passes 101 tests. Full Pytest passes 1685 tests,
|
||||
with one optional `pypdf` skip and no failures; these counts overlap. Both
|
||||
Tiny PDK PR regressions pass, including six strict simulation verdicts,
|
||||
synthesis, netlist boot and the 32-macro/common-SYS binding check. Each
|
||||
simulator passes all 28 reset scenarios, including three production DMA
|
||||
drain cases; normal-target, arbitrary-target-reset and fault-collector
|
||||
induction/SAT checks pass. Complete terminal/fault publication bindings and
|
||||
three unsafe-completion mutation tests pass without changing the reviewed
|
||||
publication SHA. RTL format/style/readiness, Ruff and diff checks pass.
|
||||
|
||||
`source.json` and `evidence.json` bind 2011 technical inputs to digest
|
||||
`f670789a2379a8d2e6c59f5ecd714ca0237bb6f1cfe749a2f29b0794d356b5f0`,
|
||||
locked tools, exact command results and retained artifacts. No warning
|
||||
baseline, metric policy, shared DMA/SDK implementation or public ABI changed.
|
||||
The lint signatures/counts match the preceding `09-30` campaign; the existing
|
||||
baseline comparison remains a non-blocking observation. STA remains unclosed:
|
||||
max WNS is -70.04 ns ICS55 and -127.01 ns IHP130. The runbook records full
|
||||
area/timing observations and limitations. Matched-image replay, full-function
|
||||
C netlist qualification, PDF promotion and physical qualification were not
|
||||
repeated for this bounded correctness repair. P5 human review/acceptance and
|
||||
all P6+ work remain separate.
|
||||
|
||||
## TINY-R2-P5 target-reset isolation repair; focused validation (2026-10-11)
|
||||
|
||||
Superseded attempt: later protocol checks rejected its response flushing and
|
||||
early B/RLAST behavior. The four focused passes below remain historically
|
||||
accurate but were insufficient to establish reset isolation.
|
||||
|
||||
Following the P5 review, the fabric now receives the explicit 23-entry target
|
||||
reset vector. A reset blocks new admission and downstream handshakes, flushes
|
||||
response spill state, and converts any accepted target session into a held
|
||||
DECERR terminal response. The existing owner credit is released only by the
|
||||
upstream RLAST/B handshake, preventing stale response replay or a permanently
|
||||
busy direction. No target map, public register, DMA capacity, clock profile or
|
||||
later phase was changed.
|
||||
|
||||
The focused command
|
||||
`PYTHONDONTWRITEBYTECODE=1 python3 -m pytest -q tests/test_tiny_r2_p5.py -k 'target_reset_isolation or concurrent_fabric'` passed 4 tests: both
|
||||
Icarus and Verilator reset-isolation tests and both existing concurrent-fabric
|
||||
tests. `make rtl-format-check rtl-style-check-all rtl-readiness-check-all`
|
||||
also passed. This is a focused implementation check; the prior P5 campaign
|
||||
reports remain source-bound to their recorded snapshots and have not been
|
||||
rewritten or relabeled. The retained focused logs are under
|
||||
`build/ics55-tiny-2026-10-10-18-58-b4aa59f3e5d9/meta/tiny-r2-p5/reset-repair-tests/`.
|
||||
|
||||
## TINY-R2-P5 implementation; validated, review pending (2026-10-10)
|
||||
|
||||
The maintainer approved the single-phase P5 plan on clean commit
|
||||
`3131762b35e0ebfcd196395f955e7c1005bd18e7`, specification blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4`. The P4 input hashes match this
|
||||
starting source, but earlier reports retain their original snapshot attribution.
|
||||
The [P5 runbook](tiny-soc-r2-concurrent-fabric.md) records target-local ownership,
|
||||
sixteen APB branches, reserved inactive SDIO owner 2, concurrent-fault accounting
|
||||
and the unchanged public ABI/clock/memory boundaries.
|
||||
|
||||
The completed campaign is under
|
||||
`build/ics55-tiny-2026-10-10-18-58-b4aa59f3e5d9/meta/tiny-r2-p5/`;
|
||||
the earlier `18-25` root retains development attempts. Full Pytest reports
|
||||
1679 passed and one optional `pypdf` skip. Both Tiny PDK PR regressions pass,
|
||||
including synthesis, netlist boot and clock/macro binding. The real CPU/DMA
|
||||
fixture records 13 overlapping DMA read/write beat cycles, 27 independent control
|
||||
completions, hart-reset isolation and abort drain on both simulators. Scoped
|
||||
target-control/fault proofs and retained P4 latency/streaming checks pass.
|
||||
|
||||
Initial image executions passed but aggregation correctly failed on an Icarus 13
|
||||
temporary-expression population-count defect. The only subsequent source change
|
||||
is P5 opt-in testbench instrumentation. `source.json` retains the original
|
||||
snapshot for the unchanged DUT/full-suite/ordinary-regression/PPA results;
|
||||
`monitor-source.json` records the corrected monitor. Only affected image
|
||||
measurements and monitor checks were repeated. `monitor-diagnosis.json` retains
|
||||
the reproduction and original discrepancy; no comparison rule was relaxed.
|
||||
|
||||
Final `report.json` has identical banked observations across simulators. Against
|
||||
repaired P4, burst1 cycles change 91306→65527 flat and 89365→65502 banked; burst16
|
||||
changes 17897→16974 and 17317→15802. CPU/copy cycles are unchanged; small
|
||||
contention/TCD/chunk256 increases remain explicit. The final combined input
|
||||
digest is `0f3ed21f6fd6e932ff2532aab8c9964e71cf4b972e4c27e2c8ca6ab1f22c1015`.
|
||||
`evidence.json` rechecks 2010 inputs and binds both snapshot scopes, six ordinary
|
||||
simulations, final matched-image runs, 15 focused/formal artifacts and reused
|
||||
unchanged Mini compatibility evidence. Library area grows 5.56%/6.95%; max WNS
|
||||
is -64.75 ns ICS55 and -111.93 ns IHP130. Timing remains unclosed/observational.
|
||||
The runbook records exact commands, source attribution, warning observations,
|
||||
measurements and unrun qualifications. Human phase acceptance is pending.
|
||||
Shared DMA/Mini/SDK behavior, dependencies and warning/metrics policy remain
|
||||
unchanged. No P6 execution or physical-frequency qualification is authorized.
|
||||
|
||||
## TINY-R2-P4 throughput repair; validated, review pending (2026-10-10)
|
||||
|
||||
Following the read-only P4 review, the maintainer approved the bounded-buffer
|
||||
repair plan for the P2 external-SRAM throughput regression. The changed Tiny
|
||||
group/frontend keep local I/D single-operation semantics, reserve external
|
||||
response capacity and overlap burst issuance/retirement; W is captured before
|
||||
macro arbitration and B follows complete commit-response drain. Common FIFO
|
||||
and register dependencies, ABI, clock/macro bindings and the pre-P5 external
|
||||
attachment remain unchanged. No shared Mini debug code is changed by this fix.
|
||||
|
||||
Fresh evidence belongs under
|
||||
`build/ics55-tiny-2026-10-10-15-15-b4aa59f3e5d9/meta/tiny-r2-p4/`.
|
||||
The preceding P4 report below remains the pre-repair comparison, and does not
|
||||
qualify these new changes. The final audit rechecks 1972 technical inputs,
|
||||
six fresh regression simulations and three immutable-image executions. Full
|
||||
Pytest reports 1659 passed and one optional `pypdf` skip. Both Tiny PDK PR
|
||||
regressions pass, including synthesis, netlist boot and clock/macro bindings.
|
||||
Streaming/backpressure/error/reset checks and response conservation/fairness
|
||||
induction pass; all six SRAM fixtures retain three-cycle local completion and
|
||||
one-cycle steady read/write beat spacing. Initial style failures and focused
|
||||
development attempts remain separate from final qualifying results.
|
||||
|
||||
Matched burst16 DMA cycles fall from 36713 to 17897 (flat) and 36489 to 17317
|
||||
(banked), reductions of 51.25% and 52.54%. All banked observations match across
|
||||
Verilator and Icarus. CPU/copy/burst1 cycles remain unchanged from pre-repair
|
||||
P4; burst1 overhead and 8.34%/4.81% burst16 overhead versus original P3 remain
|
||||
explicit. The combined input digest is
|
||||
`58daf68fbb9dee199b3085a73ef07d22eb3de6d00ba875c462e85b76b6091a0d`.
|
||||
`evidence.json` binds the source, artifacts, comparison and reused unchanged
|
||||
Mini behavioral evidence. All long gates ran once; Tiny nightly matched PR
|
||||
and was not duplicated. Setup WNS remains negative (-36.88 ns ICS55,
|
||||
-97.37 ns IHP130), with warning/metrics observations and baselines preserved.
|
||||
The [runbook](tiny-soc-r2-local-memory.md) records exact commands, measurements
|
||||
and unrun qualifications. Human review remains required; no P5 execution or
|
||||
physical-frequency qualification is implied.
|
||||
|
||||
## TINY-R2-P4 implementation and validation; review pending (2026-10-10)
|
||||
|
||||
The maintainer approved P4 preflight and implementation on clean source
|
||||
`4db27524a6282ca40d76b935415b89f043d6ea83`, specification blob
|
||||
`7e19de49d49efaafacccfa85671e314d53dd15a4`. The [P4 runbook](tiny-soc-r2-local-memory.md)
|
||||
records architecture, lifecycle, physical binding and matched-image boundaries.
|
||||
P3 results retain their original source attribution; no historical phase or
|
||||
physical qualification is automatically promoted.
|
||||
|
||||
Development evidence is under
|
||||
`build/ics55-tiny-2026-10-10-10-05-b4aa59f3e5d9/meta/tiny-r2-p4/`.
|
||||
All planned functional gates completed: 1659 Pytest passes and one optional
|
||||
`pypdf` skip; Tiny ICS55/IHP130 PR and Mini ICS55 behavioral compatibility pass.
|
||||
Both Tiny netlists pass boot and the four-group/32-macro/common-SYS binding
|
||||
checks. Local uncontended latency is three cycles; group-control induction
|
||||
passes. Setup and hold timing remain negative and observational.
|
||||
|
||||
`report.json` retains single-execution matched-binary results; the banked image
|
||||
matches exactly across Verilator and Icarus. CPU-copy cycles improve about
|
||||
19%/25% for flat/banked images, while isolated burst-16 DMA cycles increase
|
||||
about 2.2 times. This external-frontend throughput regression requires review;
|
||||
no blanket speedup or automatic phase acceptance is claimed. `evidence.json`
|
||||
rechecks 1972 source inputs and binds the gate, image, model, log and report
|
||||
artifacts. Exact commands, measurements and unrun qualifications are in the runbook.
|
||||
|
||||
External fabric stays serialized until P5, which is not authorized. Default
|
||||
Tiny stays ICS55 SAFE24 with PLL off; IHP130 is explicit compatibility.
|
||||
|
||||
## TINY-R2-P3 implementation in progress (2026-10-08–10)
|
||||
|
||||
The retained source-bound compiler/layout matrix is complete for commit
|
||||
`3e46cc80e2d2243233d284b7cd9583714b0773bb`, source digest
|
||||
`a7fc5112cd6f20df956243c4d081a6a31ede6192cd270e3c13340557b0e58776`.
|
||||
All eight configurations pass ordinary Tiny acceptance and three deterministic
|
||||
Verilator cold starts. `compat-os-flat`, `perf-o2-lto-flat` and
|
||||
`perf-o2-plain-banked` also pass three native Icarus cold starts, with exact
|
||||
cross-simulator sample identity. The structured measurement report is
|
||||
`build/ics55-tiny-performance-2026-10-09-17-10-53cc6674d532/meta/tiny-r2-p3/report.json`.
|
||||
It records software measurements only; it does not close phase acceptance,
|
||||
physical timing, hardware bank conflict or Mini integrated-DMA gates.
|
||||
|
||||
Quality evidence for that committed source is complete: full Pytest reports 1629 passed and
|
||||
one environment skip for missing `pypdf`; focused P3 tests and the embedded/RTL
|
||||
quality checks pass. Its Tiny PR regressions pass for ICS55 and IHP130, and
|
||||
Mini ICS55 behavioral-only compatibility passes. Negative STA margins and
|
||||
non-blocking lint observations remain recorded as observations.
|
||||
|
||||
Exact commands, measurements, current evidence roots and remaining qualification
|
||||
limits are in the final section of the [P3 review-fix record](tiny-soc-r2-p3-review-fixes.md).
|
||||
Human review and acceptance remain required before any R2-P4 work.
|
||||
|
||||
### Subsequent P1 race-fix follow-up
|
||||
|
||||
The approved follow-up fixes WS2812 completion between register reads and
|
||||
legacy TCD publication across an ISR lease acquisition. Current source is
|
||||
`3e46cc8` plus the two HAL fixes and deterministic host tests; the matrix above
|
||||
remains evidence for the original commit. New evidence is under
|
||||
`build/ics55-tiny-2026-10-10-09-00-b4aa59f3e5d9/meta/tiny-r2-p3-races/`.
|
||||
The two new tests fail before their respective fixes and pass afterward;
|
||||
C format/policy/host checks and 156 focused tests pass. Mini PIO compatibility
|
||||
also passes once with strict SIM_TEST_PASS and no forbidden markers. Tiny
|
||||
ICS55/IHP130 PR and Mini ICS55 behavioral regressions each pass once. Final
|
||||
`evidence.json` checks all 1287 source inputs, 487 Mini PIO compiled inputs and
|
||||
all eight ordinary regression simulations. Lint baseline differences and
|
||||
negative STA remain observations; no timing closure is claimed. See the final
|
||||
review-fix section for commands, hashes, exact paths and unrun gates.
|
||||
|
||||
Per the maintainer's follow-up instruction, long checks default to one execution;
|
||||
repeat only for a concrete failure/inconsistency or an explicit acceptance
|
||||
requirement. This follow-up does not repeat the three-cold-start compiler matrix.
|
||||
It does not waive any frozen qualification requirement or reattribute old runs.
|
||||
|
||||
### Historical development snapshot
|
||||
|
||||
The 2026-10-09 execution snapshot in the [P3 review-fix record](tiny-soc-r2-p3-review-fixes.md)
|
||||
records all eight ordinary Tiny/Verilator compiler experiments completed, with
|
||||
selected Icarus groups still running. The current-source full Pytest result is
|
||||
selected Icarus groups still running at that snapshot. The then-current full Pytest result was
|
||||
1531 passed, 4 failed, 94 fixture errors and 1 skipped; configuration-declaration
|
||||
and publication source/fixture drift remain open. IHP130 Tiny PR completes with
|
||||
and publication source/fixture drift were still open. IHP130 Tiny PR completed with
|
||||
non-blocking lint observations and negative STA margin. These results do not
|
||||
close the remaining matrix, quality or human phase-acceptance gates.
|
||||
replace the final results above or imply human phase acceptance.
|
||||
|
||||
The [P3 review-fix record](tiny-soc-r2-p3-review-fixes.md) closes the retained
|
||||
banked O2 Icarus finding: all three runs completed successfully and match the
|
||||
@@ -28,8 +500,8 @@ is bound at
|
||||
underflow/abort recovery, zero DMA starts and strict TEST_STATUS/SIM_TEST_PASS.
|
||||
Focused checks report 96 passed; C/RTL quality, Ruff and diff checks pass.
|
||||
The old Mini DMA failure remains failed/unsupported evidence, not a PIO pass.
|
||||
The full compiler/placement matrix, broader current-source regressions and human
|
||||
phase acceptance remain pending. See the review-fix record for exact commands,
|
||||
The full compiler/placement matrix and broader regressions were pending in this
|
||||
initial record; human phase acceptance remains pending. See the review-fix record for exact commands,
|
||||
artifacts, historical attribution and unrun gates.
|
||||
|
||||
The user explicitly approved the P3 preflight and implementation on source
|
||||
@@ -42,9 +514,9 @@ Original phase IDs, historical evidence and qualification limits are retained.
|
||||
|
||||
The [P3 runbook](tiny-soc-r2-software-scheduling.md) defines compiler/layout
|
||||
experiments, shared finite DMA/WS2812 service, ownership and exact commands.
|
||||
Implementation and validation are in progress; this entry does not claim
|
||||
phase completion or performance improvement. The existing GNU toolchain is
|
||||
used first, as requested; no dependency version has been changed.
|
||||
The initial entry recorded implementation and validation in progress; it did not
|
||||
claim phase completion or performance improvement. The existing GNU toolchain
|
||||
was used as requested; no dependency version has been changed.
|
||||
|
||||
Early development testing found a compressed-instruction acceptance bug:
|
||||
`rs_mcu_unmapped_probe` assembled its faulting load as 16-bit `4108`, while
|
||||
@@ -448,8 +920,8 @@ not a prerequisite to the architectural improvements in R2-P3 through R2-P5.
|
||||
| TINY-R2-P0 - Performance Contract and Roadmap Freeze | Reviewable requirements, exact old/new phase mapping, invariant package/IO counts, same-frequency CPU/main-SRAM ownership, explicit performance budgets, links and commands. Record actual documentation checks separately. | Documentation freeze only; no hardware result |
|
||||
| TINY-R2-P1 - Reproducible Baseline, Constraints and Measurements | Reviewed source/profile/lock/tool identity; current 24 MHz functional and workload baseline; clocks, reset endpoints, constraints and timing-exception audit; counters and comparison methodology. Historical WNS is a risk reference, not a refreshed measurement. | Functional/measurement baseline accepted by explicit P2 approval on 2026-10-06; timing, warning and physical gaps retained |
|
||||
| TINY-R2-P2 - Reset Distribution and CPU/SRAM Clock Feasibility | Reset distribution and payload-reset semantics; locked IHP130 main-SRAM macro timing, candidate common CPU/SRAM periods and representative paths; early clock/reset feasibility with explicit gaps. No final routed/PVT pass is implied. | Implementation and evidence ready for review; all analyzed rates retain timing failures; phase acceptance pending human review |
|
||||
| TINY-R2-P3 - Software and DMA Scheduling | Compiler and placement A/B results, finite DMA ownership, burst/chunk scheduling, WS2812 refill budget and workload correctness on the available platform. | Pending |
|
||||
| TINY-R2-P4 - Dual-Port Hazard3 and Four-Bank Local SRAM | Actual separate I/D paths, four independent 32 KiB bank frontends, SYS-clocked physical main-SRAM macros, local latency/fairness, FENCE.I, debug/reset and early inventory/SDC/macro-binding updates. | Pending |
|
||||
| TINY-R2-P3 - Software and DMA Scheduling | Compiler and placement A/B results, finite DMA ownership, burst/chunk scheduling and available-path correctness; approved option A retains product DMA/IRQ budget qualification for the platform that supplies the route. | Matrix retained on `3e46cc8`; subsequent two P1 HAL fixes and focused/compatibility checks complete in the worktree; human review/acceptance pending |
|
||||
| TINY-R2-P4 - Dual-Port Hazard3 and Four-Bank Local SRAM | Actual separate I/D paths, four independent 32 KiB bank frontends, SYS-clocked physical main-SRAM macros, local latency/fairness, FENCE.I, debug/reset and early inventory/SDC/macro-binding updates. | Implementation and planned functional validation complete on `4db2752` plus retained worktree snapshot; matched-image DMA throughput regression and human phase acceptance pending review; timing remains observational |
|
||||
| TINY-R2-P5 - Per-Target Concurrent Fabric | Cross-target concurrency, one combined transaction per target, central-DMA read/write overlap, AW/W binding, errors, simultaneous faults/counters and accepted-transfer drain. | Pending |
|
||||
| TINY-R2-P6 - Shared IP and Eight-Channel DMA Integration | Legacy P7 obligations; shared PWM reporting, I2S slave and alternate-input-route prerequisites; common ABI/HAL parity; Crypto banks/lifecycle; truthful capabilities and affected Mini compatibility. | Pending |
|
||||
| TINY-R2-P7 - Tiny RCU and Dual-Mode Clock/Reset Integration | Legacy P8 obligations with main SRAM in SYS and XPI in MEM; atomic rate changes, all actual CDC/reset barriers, clock failures, WFI leaf gating and reserved DVP controls. | Pending |
|
||||
|
||||
@@ -158,11 +158,17 @@ false-paths the canonical reset ports. Product overlays
|
||||
Qualified I/O covers JTAG, DVP (GPIO10-20), ULPI, SDRAM, SDIO, XPI, and
|
||||
asynchronous pads (UART0/1, remaining GPIO); a reviewed
|
||||
`TIMING_IO_MODE_HOOK` is mandatory in qualified mode.
|
||||
- Tiny (`tiny.tcl`): SAFE24 boot — `clk_system` (external 24 MHz) and
|
||||
`clk_jtag` only. The PLL_TOP macro is parked (EN=0), is not a clock source,
|
||||
- Tiny (`tiny.tcl`): P7 SAFE24 boot — `clk_aon` (external 24 MHz), derived
|
||||
`clk_system`, `clk_memory`, `clk_peripheral`, `clk_jtag`, and the independent
|
||||
`clk_audio` (GPIO17, 18.432 MHz). Explicit case analysis selects REF24 in all
|
||||
four RCU muxes and parks PLL_TOP (EN=0) for this scenario. The live design
|
||||
supports software transitions, but active PLL timing is not modeled here.
|
||||
In this scenario the PLL is not a clock source,
|
||||
and has no characterized timing arcs yet (see `docs/ip/tiny-soc.md`
|
||||
TINY-055); its DB/LEF/GDS/CDL views are still required for link, placement,
|
||||
and LVS. Qualified I/O covers JTAG, XPI, and asynchronous pads.
|
||||
and LVS. The legacy I/O template covers JTAG, XPI, and asynchronous pads;
|
||||
this domain inventory update does not qualify P6 I2S/SDIO board timing or
|
||||
the final QFN64 wrapper.
|
||||
|
||||
## Legacy-flow parity
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ TOP := retrosoc_tiny_asic
|
||||
|
||||
# Canonical clock domains, mirrored by tcl/common/products/tiny.tcl and
|
||||
# validated against rtl/tiny/integration/clock_reset_domains.json when the
|
||||
# commercial timing contract is generated. Tiny boots SAFE24: the PLL_TOP
|
||||
# macro is present in the netlist but parked off and is not a clock source.
|
||||
COMMERCIAL_CLOCK_DOMAINS := system jtag
|
||||
# commercial timing contract is generated. This adapter analyzes the SAFE24
|
||||
# boot scenario, explicitly constraining RCU mux selections and PLL enable.
|
||||
COMMERCIAL_CLOCK_DOMAINS := aon system memory peripheral jtag audio
|
||||
|
||||
# Qualified-I/O interface groups and the budget variables each group requires.
|
||||
COMMERCIAL_IO_INTERFACES := JTAG XPI ASYNC
|
||||
@@ -38,7 +38,7 @@ COMMERCIAL_IO_BUDGET_VARIABLES := \
|
||||
# Tiny has no bidirectional pad-mode selection requirement.
|
||||
PRODUCT_REQUIRES_IO_MODE_HOOK := NO
|
||||
|
||||
# The Tiny PLL_TOP macro is parked (EN=0) and has no characterized timing
|
||||
# In this SAFE24 scenario PLL_TOP is parked (EN=0) and has no characterized timing
|
||||
# arcs; doctor skips the qualified PLL-mode checks for this product. See
|
||||
# docs/ip/tiny-soc.md (TINY-055) for the qualification boundary.
|
||||
PRODUCT_PLL_MODE := parked
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
# retroSoC Tiny (retrosoc_tiny_asic) product overlay.
|
||||
#
|
||||
# Clock intent: the canonical contract (rtl/tiny/integration/
|
||||
# clock_reset_domains.json) owns two domains, system (SAFE24 external clock)
|
||||
# and jtag. The ICS55 PLL_TOP macro is present but parked off (EN=0) and is
|
||||
# not a clock source; it carries no characterized timing arcs yet, so no PLL
|
||||
# overlay clock is created here. See docs/ip/tiny-soc.md (TINY-055).
|
||||
# clock_reset_domains.json) owns REF24, derived SYS/MEM/PCLK, JTAG and GPIO17
|
||||
# AUDIO. This adapter covers SAFE24 boot only. RCU can enable the physical PLL
|
||||
# in functional operation, but its active timing remains unqualified.
|
||||
|
||||
namespace eval product {}
|
||||
|
||||
proc product::expected_clock_domains {} {
|
||||
return {system jtag}
|
||||
return {aon system memory peripheral jtag audio}
|
||||
}
|
||||
|
||||
proc product::custom_clock_domains {} {
|
||||
@@ -27,7 +26,7 @@ proc product::custom_clock_domains {} {
|
||||
}
|
||||
|
||||
proc product::clock_names {} {
|
||||
return {clk_system clk_jtag}
|
||||
return {clk_aon clk_system clk_memory clk_peripheral clk_jtag clk_audio clk_sys_div2 clk_sys_div4 clk_clkout_source}
|
||||
}
|
||||
|
||||
proc product::io_interface_groups {} {
|
||||
@@ -35,6 +34,31 @@ proc product::io_interface_groups {} {
|
||||
}
|
||||
|
||||
proc product::apply_clock_overlays {} {
|
||||
foreach divisor {2 4} {
|
||||
create_generated_clock -name clk_sys_div$divisor \
|
||||
-source [flow::domain_object system] -divide_by $divisor \
|
||||
[flow::required_net_driver_pin "Tiny SYS /$divisor" \
|
||||
"u_soc/u_clock_backend/s_div${divisor}_clk"]
|
||||
flow::register_clock clk_sys_div$divisor core
|
||||
}
|
||||
foreach mux {u_sys_mux u_mem_mux u_pclk_div2_mux u_pclk_mux} {
|
||||
set_case_analysis 0 [flow::required_pins "Tiny SAFE24 mux $mux" \
|
||||
"u_soc/u_clock_backend/$mux/select_i"]
|
||||
foreach {side enabled} {0 1 1 0} {
|
||||
set_case_analysis $enabled [flow::required_net_driver_pin "Tiny settled clock gate" \
|
||||
"u_soc/u_clock_backend/$mux/r_enable$side"]
|
||||
}
|
||||
}
|
||||
set_case_analysis 0 [flow::required_pins "Tiny SAFE24 PLL enable" \
|
||||
"u_soc/u_clock_backend/u_pll/gen_ecos/u_backend/u_PLL_TOP/EN"]
|
||||
foreach bit {1 2} {
|
||||
set_case_analysis 0 [flow::required_net_driver_pin "Tiny boot CLKOUT source" \
|
||||
"u_soc/u_clock_output/s_cfg_q\[$bit\]"]
|
||||
}
|
||||
create_generated_clock -name clk_clkout_source -source [flow::domain_object aon] \
|
||||
-divide_by 1 [flow::required_net_driver_pin "Tiny boot CLKOUT source clock" \
|
||||
"u_soc/u_clock_output/s_src_clk"]
|
||||
flow::register_clock clk_clkout_source core
|
||||
}
|
||||
|
||||
proc product::apply_io_constraints {} {
|
||||
|
||||
@@ -27,7 +27,7 @@ SIDE_ORDER = ("south", "east", "north", "west")
|
||||
EXPECTED_SIGNAL_PADS = 52
|
||||
CLOCK_PORTS = ("extclk_i_pad", "jtag_tck_i_pad")
|
||||
SRAM_MASTER = "RM_IHPSG13_1P_1024x32_c2_bm_bist"
|
||||
SRAM_INSTANCE = "u_soc.u_sram.gen_memory.gen_bank[{index}].u_ram.u_mem"
|
||||
SRAM_INSTANCE = "u_soc.u_sram.gen_group[{group}].u_group.gen_bank[{bank}].u_ram.u_mem"
|
||||
SRAM_COLUMNS = 8
|
||||
SRAM_ORIGIN = (400, 600)
|
||||
# Detailed routing requires an M2 track inside each bank's 0.26 um bottom-edge
|
||||
@@ -95,7 +95,7 @@ def sram_instances(capacity_kib: int) -> dict[str, tuple[list[int], str]]:
|
||||
SRAM_ORIGIN[0] + column * SRAM_PITCH[0],
|
||||
SRAM_ORIGIN[1] + row * SRAM_PITCH[1],
|
||||
]
|
||||
instances[SRAM_INSTANCE.format(index=index)] = (location, "N")
|
||||
instances[SRAM_INSTANCE.format(group=index // 8, bank=index % 8)] = (location, "N")
|
||||
return instances
|
||||
|
||||
|
||||
@@ -122,18 +122,9 @@ def macro_config(instances: dict[str, tuple[list[int], str]], header: str) -> di
|
||||
def macro_hooks(instances: dict[str, tuple[list[int], str]]) -> list[str]:
|
||||
hooks: list[str] = []
|
||||
for instance in instances:
|
||||
bracket_start = instance.find("[")
|
||||
if bracket_start >= 0:
|
||||
bracket_end = instance.index("]", bracket_start)
|
||||
instance_pattern = (
|
||||
re.escape(instance[:bracket_start])
|
||||
+ ".*"
|
||||
+ instance[bracket_start + 1 : bracket_end]
|
||||
+ ".*"
|
||||
+ re.escape(instance[bracket_end + 1 :])
|
||||
)
|
||||
else:
|
||||
instance_pattern = re.escape(instance)
|
||||
# OpenDB and synthesis may escape array brackets differently. Handle
|
||||
# every index (group and bank), retaining the exact non-index hierarchy.
|
||||
instance_pattern = ".*".join(re.escape(part) for part in re.split(r"[\[\]]", instance))
|
||||
hooks.extend(
|
||||
[
|
||||
f"{instance_pattern} VDD VSS VDDARRAY! VSS!",
|
||||
|
||||
@@ -119,9 +119,12 @@ def render(domains: list[dict[str, Any]], reset_ports: list[str]) -> str:
|
||||
if source_domain is None:
|
||||
lines.append(f"create_clock -name clk_{name} -period {period} ${pin_variable}")
|
||||
else:
|
||||
divide_by = sta.get("divide_by", 1)
|
||||
if not isinstance(divide_by, int) or isinstance(divide_by, bool) or divide_by < 1:
|
||||
raise ValueError("generated clock division must be a positive integer")
|
||||
lines.append(
|
||||
f"create_generated_clock -name clk_{name} -source ${pin_variables[source_domain]} "
|
||||
f"-divide_by 1 ${pin_variable}"
|
||||
f"-divide_by {divide_by} ${pin_variable}"
|
||||
)
|
||||
lines.append("")
|
||||
|
||||
@@ -175,10 +178,52 @@ def main() -> int:
|
||||
parser.add_argument("--domains", type=Path, required=True)
|
||||
parser.add_argument("--pin-map", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--xin-hz", type=int, default=24000000)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
domains, reset_ports = parse_document(args.domains, args.pin_map)
|
||||
atomic_write(args.output, render(domains, reset_ports))
|
||||
document = json.loads(args.domains.read_text())
|
||||
p7 = document.get("clock_contract") == "TINY-R2-P7"
|
||||
if p7 and args.xin_hz not in (24000000, 48000000, 96000000):
|
||||
raise ValueError("unsupported Tiny external clock")
|
||||
if p7 and args.xin_hz != 24000000:
|
||||
aon = next(domain for domain in domains if domain["name"] == "aon")
|
||||
external = {**aon, "name": "external", "sta": {**aon["sta"],
|
||||
"period_ns": 1e9 / args.xin_hz}}
|
||||
aon["sta"] = {"source_domain": "external", "period_ns": 1e9 / 24000000,
|
||||
"divide_by": args.xin_hz // 24000000, "async_group": "core",
|
||||
"pin": "u_soc.u_clock_backend.gen_ref_divided.u_ref_div/clk_o"}
|
||||
domains.insert(0, external)
|
||||
if p7:
|
||||
# These sources run even while the muxes select their undivided
|
||||
# inputs. Their handover synchronizers still require real clocks.
|
||||
for divisor in (2, 4):
|
||||
domains.append({"name": f"sys_div{divisor}", "sta": {
|
||||
"source_domain": "system", "period_ns": 1e9 * divisor / 24000000,
|
||||
"divide_by": divisor, "async_group": "core", "object_type": "net_driver",
|
||||
"net": f"u_soc.u_clock_backend.s_div{divisor}_clk"}})
|
||||
domains.append({"name": "clkout_source", "sta": {
|
||||
"source_domain": "aon", "period_ns": 1e9 / 24000000,
|
||||
"divide_by": 1, "async_group": "core", "object_type": "net_driver",
|
||||
"net": "u_soc.u_clock_output.s_src_clk"}})
|
||||
result = render(domains, reset_ports)
|
||||
if p7:
|
||||
result += "\n# P7 SAFE24 boot scenario; this does not qualify active PLL timing.\n"
|
||||
for mux in ("u_sys_mux", "u_mem_mux", "u_pclk_div2_mux", "u_pclk_mux"):
|
||||
result += (f"set_case_analysis 0 [require_pins {{P7 SAFE24 selection}} "
|
||||
f"{{u_soc.u_clock_backend.{mux}/select_i}}]\n")
|
||||
# select_i passes through sequential handshake state. A static
|
||||
# mode must also select its settled gate state; setting only
|
||||
# the request cannot prune the other live clock in STA.
|
||||
for side, enabled in ((0, 1), (1, 0)):
|
||||
result += (f"set_case_analysis {enabled} [require_net_driver_pin "
|
||||
f"{{P7 SAFE24 settled gate}} "
|
||||
f"{{u_soc.u_clock_backend.{mux}/r_enable{side}}}]\n")
|
||||
result += "# CLKOUT retains its reset REF24 source in this boot scenario.\n"
|
||||
for bit in (1, 2):
|
||||
result += (f"set_case_analysis 0 [require_net_driver_pin {{P7 CLKOUT source}} "
|
||||
f"{{u_soc.u_clock_output.s_cfg_q_{bit}_}}]\n")
|
||||
atomic_write(args.output, result)
|
||||
except (OSError, ValueError, json.JSONDecodeError) as error:
|
||||
parser.error(str(error))
|
||||
return 0
|
||||
|
||||
@@ -16,14 +16,14 @@ include $(ROOT_PATH)/physical/smoke/sta/opensta/pdk_timing.mk
|
||||
|
||||
$(OPENSTA_SDC): $(OPENSTA_SDC_GEN) $(OPENSTA_DOMAIN_MAP) $(OPENSTA_PIN_MAP) | manifest
|
||||
@mkdir -p $(dir $@)
|
||||
python3 $(OPENSTA_SDC_GEN) --domains $(OPENSTA_DOMAIN_MAP) --pin-map $(OPENSTA_PIN_MAP) --output $@
|
||||
python3 $(OPENSTA_SDC_GEN) --domains $(OPENSTA_DOMAIN_MAP) --pin-map $(OPENSTA_PIN_MAP) --output $@ --xin-hz $(EXT_CLK_HZ)
|
||||
|
||||
sta: $(OPENSTA_SDC) | manifest
|
||||
@mkdir -p $(STA_BUILD_ROOT)
|
||||
ifeq ($(TINY_SAFE24_PLL_OFF),YES)
|
||||
python3 $(ROOT_PATH)/scripts/tiny_ics55_platform.py --variant-root $(VARIANT_ROOT) verify-netlist \
|
||||
ifeq ($(SOC),TINY)
|
||||
python3 $(ROOT_PATH)/scripts/tiny_r2_p7.py --variant-root $(VARIANT_ROOT) verify-netlist \
|
||||
--netlist $(OPENSTA_NETLIST) --config $(OPENSTA_CONFIG) \
|
||||
--output $(SYN_BUILD_ROOT)/tiny-ics55-netlist.json
|
||||
--output $(SYN_BUILD_ROOT)/tiny-r2-p7-netlist.json
|
||||
endif
|
||||
@for input in $(OPENSTA_NETLIST) $(OPENSTA_LIBERTY) $(OPENSTA_LINK_LIBS) $(OPENSTA_SRAM_LIBS) $(OPENSTA_SDC) $(OPENSTA_CONFIG); do \
|
||||
test -f "$$input" || { echo "OpenSTA input missing: $$input" >&2; exit 1; }; \
|
||||
@@ -45,7 +45,7 @@ endif
|
||||
--env OPENSTA_TOP=$(OPENSTA_TOP) --env OPENSTA_NETLIST=$(OPENSTA_NETLIST) --env OPENSTA_LIBERTY=$(OPENSTA_LIBERTY) \
|
||||
--env 'OPENSTA_LINK_LIBS=$(OPENSTA_LINK_LIBS)' --env 'OPENSTA_SRAM_LIBS=$(OPENSTA_SRAM_LIBS)' \
|
||||
--env OPENSTA_SDC=$(OPENSTA_SDC) --env OPENSTA_REPORT=$(OPENSTA_REPORT) \
|
||||
--env OPENSTA_METRICS=$(OPENSTA_METRICS) --env OPENSTA_TINY_ICS55=$(TINY_SAFE24_PLL_OFF) -- \
|
||||
--env OPENSTA_METRICS=$(OPENSTA_METRICS) --env OPENSTA_TINY_ICS55=$(TINY_SAFE24_PLL_OFF) --env OPENSTA_TINY_P7=$(TINY_R2_P7) -- \
|
||||
$(OPENSTA) -no_init -exit -threads $(OPENSTA_THREADS) $(ROOT_PATH)/physical/smoke/sta/opensta/opensta.tcl
|
||||
|
||||
.PHONY: sta
|
||||
@@ -20,6 +20,13 @@ if {[info exists ::env(OPENSTA_TOP)] && $::env(OPENSTA_TOP) ne ""} {
|
||||
}
|
||||
link_design $top_design
|
||||
read_sdc $::env(OPENSTA_SDC)
|
||||
if {$top_design eq "retrosoc_tiny_asic"} {
|
||||
if {[info exists ::env(OPENSTA_TINY_P7)] && $::env(OPENSTA_TINY_P7) eq "YES"} {
|
||||
source [file join [file dirname [info script]] tiny_r2_p7_checks.tcl]
|
||||
} else {
|
||||
source [file join [file dirname [info script]] tiny_r2_p4_checks.tcl]
|
||||
}
|
||||
}
|
||||
if {[info exists ::env(OPENSTA_TINY_ICS55)] && $::env(OPENSTA_TINY_ICS55) eq "YES"} {
|
||||
source [file join [file dirname [info script]] tiny_ics55_checks.tcl]
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
set audit_dir [file dirname $::env(OPENSTA_REPORT)]
|
||||
set pll [get_cells -hierarchical -filter {ref_name == PLL_TOP}]
|
||||
set ram [get_cells -hierarchical -filter {ref_name == ics55_ecos_sram_1024x32_m8}]
|
||||
if {[llength $pll] != 1 || [llength $ram] != 32} { error "Tiny ICS55 macro binding mismatch" }
|
||||
if {[llength $pll] != 1 || [llength $ram] != 38} { error "Tiny ICS55 macro binding mismatch" }
|
||||
if {[llength [get_clocks clk_system]] != 1} { error "Tiny SYS clock missing" }
|
||||
report_clock_properties > $audit_dir/clocks.rpt
|
||||
check_setup -verbose > $audit_dir/coverage.rpt
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# P4 structural timing prerequisites, common to both supported Tiny PDKs.
|
||||
# Negative timing remains observational; missing/incorrect clock objects do not.
|
||||
set p4_dir [file dirname $::env(OPENSTA_REPORT)]
|
||||
set p4_ram [get_cells -hierarchical -filter {ref_name == RM_IHPSG13_1P_1024x32_c2_bm_bist}]
|
||||
set p4_clock_pin A_CLK
|
||||
if {[llength $p4_ram] == 0} {
|
||||
set p4_ram [get_cells -hierarchical -filter {ref_name == ics55_ecos_sram_1024x32_m8}]
|
||||
set p4_clock_pin CLK
|
||||
}
|
||||
if {[llength $p4_ram] != 38} { error "P6 requires 32 main SRAM and six private Crypto macros" }
|
||||
set p6_all_ram $p4_ram
|
||||
set p4_ram {}
|
||||
set p6_crypto {}
|
||||
set p6_crypto_expected {}
|
||||
for {set bank 0} {$bank < 6} {incr bank} {
|
||||
lappend p6_crypto_expected [format {u_soc.u_crypto.u_storage.gen_bank[%d].gen_macro.u_sram.u_mem} $bank]
|
||||
}
|
||||
set p6_crypto_seen {}
|
||||
foreach cell $p6_all_ram {
|
||||
set name [string map {/ .} [get_full_name $cell]]
|
||||
set is_crypto 0
|
||||
foreach expected $p6_crypto_expected {
|
||||
if {[string equal [string range $name end-[expr {[string length $expected]-1}] end] $expected]} {
|
||||
lappend p6_crypto_seen $expected
|
||||
set is_crypto 1
|
||||
}
|
||||
}
|
||||
if {$is_crypto} { lappend p6_crypto $cell } else { lappend p4_ram $cell }
|
||||
}
|
||||
if {[llength $p4_ram] != 32 || [lsort $p6_crypto_seen] ne [lsort $p6_crypto_expected]} {
|
||||
error "P6 private/main SRAM hierarchy mismatch"
|
||||
}
|
||||
set p4_expected {}
|
||||
for {set group 0} {$group < 4} {incr group} {
|
||||
for {set bank 0} {$bank < 8} {incr bank} {
|
||||
lappend p4_expected [format {u_soc.u_sram.gen_group[%d].u_group.gen_bank[%d].u_ram.u_mem} $group $bank]
|
||||
}
|
||||
}
|
||||
set p4_seen {}
|
||||
foreach cell $p4_ram {
|
||||
set name [string map {/ .} [get_full_name $cell]]
|
||||
foreach expected $p4_expected {
|
||||
if {[string equal [string range $name end-[expr {[string length $expected]-1}] end] $expected]} {
|
||||
lappend p4_seen $expected
|
||||
}
|
||||
}
|
||||
}
|
||||
if {[lsort $p4_seen] ne [lsort $p4_expected]} { error "P4 macro group hierarchy mismatch" }
|
||||
set p4_source [get_pins -quiet {u_clock_buffer/clk_o}]
|
||||
if {[llength $p4_source] != 1} { error "P4 SYS source missing" }
|
||||
set p4_direct {}
|
||||
foreach pin [get_fanout -from $p4_source -flat -pin_levels 1 -trace_arcs all] {
|
||||
dict set p4_direct [get_full_name $pin] 1
|
||||
}
|
||||
set p4_clock_report [open $p4_dir/p4-clock-bindings.rpt w]
|
||||
foreach cell [concat $p4_ram $p6_crypto] {
|
||||
set clocks {}
|
||||
foreach pin [get_pins -of_objects $cell] {
|
||||
if {[string match "*/$p4_clock_pin" [get_full_name $pin]]} { lappend clocks $pin }
|
||||
}
|
||||
if {[llength $clocks] != 1} { error "P4 macro clock pin missing" }
|
||||
set name [get_full_name [lindex $clocks 0]]
|
||||
if {![dict exists $p4_direct $name]} { error "P4 SRAM clock is not direct SYS: $name" }
|
||||
puts $p4_clock_report $name
|
||||
}
|
||||
set p4_cpu [get_pins -hierarchical -quiet {*u_hazard3_cpu_2port*/CLK *u_hazard3_cpu_2port*/CK *u_hazard3_cpu_2port*/CKN}]
|
||||
set p4_front [get_pins -hierarchical -quiet {*u_cpu_mem*/CLK *u_cpu_mem*/CK *u_cpu_mem*/CKN}]
|
||||
if {[llength $p4_cpu] == 0 || [llength $p4_front] == 0} { error "P4 CPU/frontend clock endpoints missing" }
|
||||
foreach pin [concat $p4_cpu $p4_front] {
|
||||
set name [get_full_name $pin]
|
||||
if {![dict exists $p4_direct $name]} { error "P4 CPU/frontend does not share SYS: $name" }
|
||||
}
|
||||
puts $p4_clock_report "CPU clock endpoints: [llength $p4_cpu]"
|
||||
puts $p4_clock_report "Frontend clock endpoints: [llength $p4_front]"
|
||||
close $p4_clock_report
|
||||
puts "TINY_R2_P4_BINDING_PASS: four groups, 32 macros, common CPU/SRAM SYS; not timing qualification"
|
||||
puts "TINY_R2_P6_BINDING_PASS: six private Crypto macros on SAFE24 PCLK; no capacity alias"
|
||||
@@ -0,0 +1,22 @@
|
||||
# P7 uses a dedicated, provenance-checked Python macro/clock audit. Historical
|
||||
# P1/P4 checks retain their direct-SYS/parked-PLL assumptions unchanged.
|
||||
set p7_dir [file dirname $::env(OPENSTA_REPORT)]
|
||||
foreach clock {clk_aon clk_system clk_memory clk_peripheral clk_audio clk_jtag clk_sys_div2 clk_sys_div4 clk_clkout_source} {
|
||||
if {[llength [get_clocks -quiet $clock]] != 1} { error "P7 clock missing: $clock" }
|
||||
}
|
||||
set p7_pll [get_cells -hierarchical -quiet -filter {ref_name == PLL_TOP}]
|
||||
if {[llength $p7_pll] > 1} { error "P7 contains multiple PLL macros" }
|
||||
if {[llength $p7_pll] == 1} {
|
||||
# The analysis is explicitly the cold SAFE24 boot operating state.
|
||||
set p7_enable [get_pins -quiet "[get_full_name [lindex $p7_pll 0]]/EN"]
|
||||
if {[llength $p7_enable] != 1} { error "P7 PLL enable pin missing" }
|
||||
set_case_analysis 0 $p7_enable
|
||||
}
|
||||
report_clock_properties > $p7_dir/clocks.rpt
|
||||
check_setup -verbose > $p7_dir/coverage.rpt
|
||||
report_check_types -recovery -removal -min_pulse_width -min_period -max_slew -max_capacitance -max_fanout -violators -verbose > $p7_dir/constraint-violations.rpt
|
||||
foreach domain {system memory peripheral aon} {
|
||||
report_checks -path_group clk_$domain -path_delay max -group_path_count 20 -fields {capacitance slew fanout} > $p7_dir/$domain-setup.rpt
|
||||
report_checks -path_group clk_$domain -path_delay min -group_path_count 20 -fields {capacitance slew fanout} > $p7_dir/$domain-hold.rpt
|
||||
}
|
||||
puts "TINY_R2_P7_STA_OBSERVATION: SAFE24 boot only; not active PLL, routed or PVT qualification"
|
||||
@@ -165,7 +165,7 @@ yosys tee -q -o "${report_dir}/${proj_name}_area_logic.rpt" stat -top $top_desig
|
||||
|
||||
# final netlist
|
||||
yosys write_verilog -noattr -noexpr -nohex -nodec $netlist
|
||||
if {$soc == "TINY" && $pdk == "ICS55"} {
|
||||
if {$soc == "TINY"} {
|
||||
yosys write_json ${netlist}.json
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ gen_synth_filelist: $(SV_FLIST)
|
||||
## Synthesize netlist using Yosys
|
||||
synth: $(NETLIST) | manifest
|
||||
|
||||
$(NETLIST): $(SV_FLIST) $(YOSYS_SCRIPTS)
|
||||
$(NETLIST): $(SV_FLIST) $(YOSYS_SCRIPTS) | manifest
|
||||
@mkdir -p $(YOSYS_OUT)
|
||||
@mkdir -p $(YOSYS_TMP)
|
||||
@mkdir -p $(YOSYS_RPT)
|
||||
@@ -74,9 +74,9 @@ $(NETLIST): $(SV_FLIST) $(YOSYS_SCRIPTS)
|
||||
--env REPORTS=$(YOSYS_RPT) --env NETLIST=$(NETLIST) -- \
|
||||
timeout --foreground --kill-after=5s $(YOSYS_TIMEOUT)s \
|
||||
yosys -t --perffile $(YOSYS_BUILD)/yosys-perf.json -c $(YOSYS_DIR)/script/synth.tcl
|
||||
ifeq ($(SOC)-$(PDK),TINY-ICS55)
|
||||
python3 $(ROOT_PATH)/scripts/tiny_ics55_platform.py --variant-root $(VARIANT_ROOT) audit-netlist \
|
||||
--netlist $(NETLIST) --config $(NETLIST_CONFIG) --output $(YOSYS_BUILD)/tiny-ics55-netlist.json
|
||||
ifeq ($(SOC),TINY)
|
||||
python3 $(ROOT_PATH)/scripts/tiny_r2_p7.py --variant-root $(VARIANT_ROOT) audit-netlist \
|
||||
--netlist $(NETLIST) --config $(NETLIST_CONFIG) --output $(YOSYS_BUILD)/tiny-r2-p7-netlist.json
|
||||
endif
|
||||
|
||||
$(NETLIST_DEBUG): $(NETLIST)
|
||||
|
||||
@@ -4459,7 +4459,8 @@
|
||||
"RS_ETIMEOUT": -4,
|
||||
"RS_EIO": -5,
|
||||
"RS_ENOTSUP": -6,
|
||||
"RS_EFORMAT": -7
|
||||
"RS_EFORMAT": -7,
|
||||
"RS_EBUSY": -8
|
||||
},
|
||||
"meanings": {
|
||||
"RS_OK": "Operation completed under that API contract.",
|
||||
@@ -4469,7 +4470,8 @@
|
||||
"RS_ETIMEOUT": "Bounded operation timed out.",
|
||||
"RS_EIO": "I/O operation failed.",
|
||||
"RS_ENOTSUP": "Operation unsupported.",
|
||||
"RS_EFORMAT": "Input format rejected."
|
||||
"RS_EFORMAT": "Input format rejected.",
|
||||
"RS_EBUSY": "Resource or lifecycle operation is busy; retry after the owning operation completes."
|
||||
},
|
||||
"observation": "Signed API return value. Exact triggering conditions depend on the called function; the enum definition does not make every code reachable from every API.",
|
||||
"handling": "Check the return before using output values. No hardware W1C applies to a C return value; preserve the relevant peripheral status if diagnosis requires it.",
|
||||
|
||||
@@ -11,9 +11,9 @@ All **39 frozen entries / 14 IP chapters** are reviewed below. Register, address
|
||||
| 3 | Configuration and Scope / 2 | Covered. IHP130, 128 KiB, 24 MHz target, four DMA channels; hardware RV32IMC versus default RV32IM firmware. | [ihp130-tiny.mk](../../../configs/ci/ihp130-tiny.mk), [retrosoc_tiny.sv](../../../rtl/tiny/top/retrosoc_tiny.sv) | Use the committed profile and identity; keep deferred interfaces and physical claims excluded. |
|
||||
| 4 | Reading and Evidence Conventions / 2 | Covered. Product-specific organization, navigation or revision control; no additional hardware capability. | [datasheet.typ](../../../publications/datasheets/tiny/datasheet.typ), [structure-contract.json](../../../publications/datasheets/tiny/structure-contract.json) | Retain the declared scope, complete source links and independent Tiny identity when updating this section. |
|
||||
| 5 | System Architecture / 17 | Covered. Product-specific organization, navigation or revision control; no additional hardware capability. | [datasheet.typ](../../../publications/datasheets/tiny/datasheet.typ), [structure-contract.json](../../../publications/datasheets/tiny/structure-contract.json) | Retain the declared scope, complete source links and independent Tiny identity when updating this section. |
|
||||
| 6 | Processor and Integration / 17 | Covered. One RV32IMC MCU hart, A disabled, direct AHB-Lite/AXI32 adapter and debug reset boundary. | [retrosoc_tiny.sv](../../../rtl/tiny/top/retrosoc_tiny.sv), [mgmt_core_wrapper.sv](../../../rtl/ip/core/mgmt_core_wrapper.sv) | Retain actual wrapper parameters; do not infer firmware ISA flags from the hardware C extension. |
|
||||
| 6 | Processor and Integration / 17 | Working-source P4 update: dual-port RV32IMC hart, A disabled, independent local I/D and tagged slow adapter. Page number belongs to the earlier delivered PDF. | [retrosoc_tiny.sv](../../../rtl/tiny/top/retrosoc_tiny.sv), [tiny_cpu_wrapper.sv](../../../rtl/tiny/top/tiny_cpu_wrapper.sv) | Retain actual wrapper parameters; revalidate publication pages separately before delivery. |
|
||||
| 7 | Clock, Reset and Operating State / 18 | Covered. System and asynchronous JTAG domains; RTC/WDG share the system clock. | [clock_reset_domains.json](../../../rtl/tiny/integration/clock_reset_domains.json), [retrosoc_tiny.sv](../../../rtl/tiny/top/retrosoc_tiny.sv) | Obtain CDC/RDC and clock/power evidence separately; do not claim independent sleep timing. |
|
||||
| 8 | Bus Transactions, Arbitration and Errors / 19 | Covered. One globally active transaction, round-robin acceptance, saved ownership, bounded legal bursts and error/drain behavior. | [tiny_axi4_fabric.sv](../../../rtl/tiny/top/tiny_axi4_fabric.sv), [axi4_error_slave.sv](../../../rtl/ip/interconnect/axi4_error_slave.sv) | Keep local IP capability separate from end-to-end fabric admission; no unlimited liveness guarantee. |
|
||||
| 8 | Bus Transactions, Arbitration and Errors / 19 | P5 source draft updated: target-local ownership, bounded independent DMA R/W, separate APB branches and concurrent fault count. | [tiny_axi4_fabric.sv](../../../rtl/tiny/top/tiny_axi4_fabric.sv), [tiny_axi4_target.sv](../../../rtl/tiny/top/tiny_axi4_target.sv) | Page19 belongs to the prior PDF; no new PDF or unconditional liveness claim. SDIO owner2 is reserved only. |
|
||||
| 9 | Memory Map and Access Conventions / 21 | Covered. Twenty canonical address windows, including alias versus physical-capacity distinctions. | [memory_map.json](../../../rtl/tiny/address_map/memory_map.json) | Reconcile every source-map change; do not use unmapped holes as scratch memory. |
|
||||
| 10 | Interrupt and DMA Request Routing / 22 | Covered. Fourteen allocated core causes, thirty external positions, enabled DMA request map and channel conventions. | [soc_topology.json](../../../rtl/tiny/integration/soc_topology.json), [dma_math.c](../../../crt/src/hal/dma_math.c) | Keep core input bits, external ordinals, CSR positions and DMA selectors distinct. |
|
||||
| 11 | Peripherals / 23 | Covered. Fourteen IP chapters and 337 source-extracted register definitions, with instance-specific routing. | [catalog.json](../../../publications/datasheets/tiny/catalog.json), [tiny_reference.py](../../../publications/tiny_reference.py) | Update source inventory, frozen register keys and rendered-coverage checks together after reviewed ABI changes. |
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
# Tiny Gen1 v0.1 DRAFT content review
|
||||
|
||||
The publication describes the independent IHP130 Tiny profile: one RV32IMC
|
||||
Hazard3 with A disabled, RV32IM default firmware, 128 KiB SRAM, 24 MHz target,
|
||||
The publication describes the independent IHP130 Tiny profile: one dual-port
|
||||
RV32IMC Hazard3 with A disabled, RV32IM default firmware, 128 KiB SRAM in four
|
||||
independently serviced 32 KiB groups, 24 MHz target,
|
||||
four DMA channels and AXI32/APB4. Rill (清溪) is the selected prototype brand.
|
||||
The font/palette/grid are inherited as design rules; product facts are not
|
||||
inherited from Mini's descriptions or qualification records.
|
||||
|
||||
The P4 working-source update changes CPU/local-SRAM bindings and the affected
|
||||
draft architecture prose/figure. It does not advance `tiny.json.source_revision`,
|
||||
rebuild or relabel a delivered PDF, or add hardware qualification. A later
|
||||
publication release still requires source review, snapshot refresh and PDF checks.
|
||||
|
||||
| Area | Review and publication decision | Follow-up boundary |
|
||||
| --- | --- | --- |
|
||||
| CPU and startup | Publish the actual C/M extensions, disabled A, CSR-enabled firmware and Tiny guard around PSRAM setup. | Keep compiler target separate from implemented ISA; a reset vector is not a completed boot. |
|
||||
| Fabric | Document one globally active CPU/DMA read or write, saved ownership, naturally aligned bounded bursts and terminal response/drain. | Do not claim arbitrary AXI4 features, independent read/write concurrency or unrestricted liveness. |
|
||||
| Fabric | P5 draft: independent target ownership, one combined CPU slow operation, DMA one read/one write, 16 APB branches and lossless concurrent-fault accounting. Owner2 is reserved, inactive SDIO. | No SDIO integration, arbitrary AXI4 features or unconditional liveness claim. Snapshot/PDF revision is not advanced. |
|
||||
| Address/IRQ/pads | Derive all 20 regions, 14 allocated core causes and 52 logical signal pads; retain 32 GPIO alternate entries. | Logical pads are not package pin numbers or a board schematic. |
|
||||
| IP/register scope | Fourteen chapters, thirteen unique register families; Tiny SYSCTRL is decoded independently and ARCHINFO overrides the SoC identity. | Reject missing/extra decode and defaults belonging to other products. |
|
||||
| DMA | Four channels, request mask 0x07F9, no stream modes, 64-byte descriptors and source-derived field layout. | **Discovery discrepancy:** the four-bit maximum-burst field reads zero after truncating 16. Publish that value and the actual 16-beat limit separately; propose a future ABI/RTL review, do not change RTL here. |
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
- JTAG debug with coordinated hart reset.
|
||||
|
||||
*Memory and interconnect*
|
||||
- *128 KiB SRAM*, 32 banks of 4 KiB.
|
||||
- *128 KiB SRAM*, four independently serviced 32 KiB groups backed by 32 banks of 4 KiB.
|
||||
- Native AXI32 memory paths and one APB4 island.
|
||||
- CPU and DMA share one active transaction globally.
|
||||
- Independent local instruction/data ports and target-local external ownership.
|
||||
- XPI NOR boot and SRAM-resident application layout.
|
||||
|
||||
*DMA and control*
|
||||
@@ -103,16 +103,18 @@ The document uses the approved Mini visual language; all product facts and sourc
|
||||
|
||||
= System Architecture
|
||||
== Processor and Integration <tiny-core>
|
||||
Hazard3 is hart zero. The shared wrapper selects the C and M extensions and disables A for Tiny. Its AHB-Lite bus terminates
|
||||
at a direct AXI32 adapter. JTAG supports the implemented halt/resume, register and system-bus debug path; debug hart reset
|
||||
waits for the adapter to become idle instead of abandoning an accepted transaction.
|
||||
Hazard3 is hart zero. The locked dual-port wrapper selects the C and M extensions and disables A for Tiny. Instruction fetch
|
||||
and load/store use independent AHB ports through separate local SRAM frontends; non-SRAM accesses use the tagged slow path.
|
||||
JTAG supports halt/resume, register access and halted-hart abstract-command memory access, without an independent system-bus master.
|
||||
Debug hart reset first halts the hart and drains accepted local I/D and slow-path responses. SRAM and unrelated DMA work stay active.
|
||||
|
||||
The system has no application hart, MMU/Linux platform, hardware cache-coherent multicore organization or product extension
|
||||
slots. CPU-visible SRAM, XPI and APB routes are the implemented interconnect. The single-hart architecture does not remove
|
||||
the need for software/DMA buffer ownership and fences.
|
||||
#architecture()
|
||||
#source-note("rtl/tiny/top/retrosoc_tiny.sv",title:"Tiny product integration and parameters")
|
||||
#source-note("rtl/ip/core/mgmt_core_wrapper.sv",title:"CPU ISA, AHB adapter and debug wrapper")
|
||||
#source-note("rtl/tiny/top/tiny_cpu_wrapper.sv",title:"Dual-port CPU ISA, AHB ports and debug wrapper")
|
||||
#source-note("rtl/tiny/top/tiny_sram.sv",title:"Four local SRAM groups and external attachment")
|
||||
|
||||
== Clock, Reset and Operating State <tiny-clock>
|
||||
CPU, AXI, APB, RTC and watchdog share the configured 24 MHz system clock. CLINT derives a 1 MHz tick. JTAG has its own
|
||||
@@ -130,9 +132,18 @@ advertised as a qualified voltage/frequency operating point.
|
||||
#source-note("rtl/tiny/integration/clock_reset_domains.json",title:"Clock/reset inventory and debug crossings")
|
||||
|
||||
== Bus Transactions, Arbitration and Errors <tiny-bus>
|
||||
The two initiators are CPU and DMA. They share *one active read or write transaction globally*. The fabric saves source,
|
||||
direction, address and attributes, forwards the request, and retains ownership until the terminal B or RLAST handshake.
|
||||
Read/write request arbitration is round-robin; it is not a throughput guarantee or an unrestricted liveness guarantee.
|
||||
The two active external initiators are CPU slow path and DMA. A third ingress is reserved for future SDIO integration and
|
||||
has no active producer. Each SRAM group, XPI memory endpoint and APB peripheral has independent transaction ownership.
|
||||
CPU slow traffic admits one combined operation; DMA can have one read and one write outstanding across different targets.
|
||||
Each target admits one combined read or write. CPU local instruction/data requests remain independently arbitrated within
|
||||
each SRAM group. Saved ownership includes accepted address and response buffers and lasts through the upstream B/RLAST handshake.
|
||||
Owner arbitration is round-robin with fair direction selection. Progress bounds require a running clock and peer progress.
|
||||
Separate APB bridges keep independent controls outside a FIFO-waiting peripheral's transaction.
|
||||
|
||||
Fault accounting counts each failed transaction once, including errors before the final read beat. Simultaneous events
|
||||
increment the saturating count individually; first-fault metadata uses ascending owner, instruction before data, then read
|
||||
before write. CPU is owner0, DMA owner1, and owner2 is reserved. FAULT_DETAIL retains raw AXI response2/3. Clearing validity
|
||||
does not clear the count, and a simultaneous hardware event wins over clear.
|
||||
|
||||
Memory transfers support naturally aligned 1/2/4-byte beats and up to 16 INCR beats. Single-beat FIXED is also admitted.
|
||||
The complete address span must remain within one decoded target and one 4 KiB page without overflow. MMIO accepts only
|
||||
|
||||
@@ -26,21 +26,22 @@
|
||||
})
|
||||
}
|
||||
#let architecture() = diagram("tiny-architecture",schematic((
|
||||
(5,4,65,19,[Hazard3 · hart 0 \ RV32IMC · A disabled]),
|
||||
(5,4,65,19,[Hazard3 dual-port · hart 0 \ RV32IMC · A disabled]),
|
||||
(104,4,63,19,[JTAG / debug transport \ External TCK domain]),
|
||||
(5,37,65,15,[AHB-Lite → AXI32 adapter]),
|
||||
(5,37,65,15,[I/D decode + slow adapter]),
|
||||
(104,37,63,15,[Four-channel DMA \ AXI32 master]),
|
||||
(30,69,112,19,[Tiny AXI32 fabric \ One active transaction globally]),
|
||||
(0,110,40,22,[128 KiB SRAM \ 32 × 4 KiB]),
|
||||
(30,69,112,19,[Tiny AXI32 fabric \ Independent target ownership]),
|
||||
(0,110,40,22,[128 KiB SRAM \ 4 × 32 KiB groups]),
|
||||
(44,110,40,22,[XPI read path \ Flash alias / NOR]),
|
||||
(88,110,40,22,[APB4 bridge \ 16 targets]),
|
||||
(88,110,40,22,[16 APB4 branches \ One per peripheral]),
|
||||
(132,110,40,22,[Error responders \ DECERR / SLVERR]),
|
||||
),(
|
||||
((104,13),(70,13)),((37,23),(37,37)),
|
||||
((5,44),(0,44),(0,103),(6,103),(6,110)),
|
||||
((37,52),(37,61),(60,61),(60,69)),((135,52),(135,61),(112,61),(112,69)),
|
||||
((45,88),(45,99),(20,99),(20,110)),((70,88),(70,103),(64,103),(64,110)),
|
||||
((103,88),(103,103),(108,103),(108,110)),((127,88),(127,99),(152,99),(152,110)),
|
||||
),height:134),[Tiny Gen1 integration. System logic runs from the configured 24 MHz clock; JTAG is asynchronous.])
|
||||
),height:134),[Tiny Gen1 integration. The left branch represents independent local I/D paths bypassing the external fabric. System logic uses the configured 24 MHz clock; JTAG is asynchronous.])
|
||||
|
||||
#let ip-diagram(entry) = {
|
||||
let children=entry.nodes.slice(1)
|
||||
|
||||
@@ -98,7 +98,12 @@
|
||||
"uart1": 26
|
||||
},
|
||||
"sources": [
|
||||
"rtl/ip/core/mgmt_core_wrapper.sv",
|
||||
"rtl/tiny/top/tiny_cpu_wrapper.sv",
|
||||
"rtl/tiny/top/tiny_cpu_mem.sv",
|
||||
"rtl/tiny/top/tiny_sram.sv",
|
||||
"rtl/tiny/top/tiny_sram_group.sv",
|
||||
"rtl/tiny/top/tiny_sram_axi4.sv",
|
||||
"rtl/tiny/top/tiny_sram_port_if.sv",
|
||||
"rtl/ip/core/mgmt_debug_wrapper.sv",
|
||||
"rtl/ip/core/mgmt_debug_reset.sv",
|
||||
"rtl/ip/interconnect/ahbl2axi4.sv",
|
||||
@@ -112,19 +117,19 @@
|
||||
"app/apps/bringup/tiny.mk",
|
||||
"app/apps/ci_smoke/tiny.mk",
|
||||
"scripts/generate_tiny.py",
|
||||
"tests/test_tiny.py"
|
||||
"tests/test_tiny.py",
|
||||
"rtl/tiny/top/tiny_axi4_target.sv",
|
||||
"rtl/tiny/top/tiny_fault_collector.sv"
|
||||
],
|
||||
"bindings": [
|
||||
{
|
||||
"file": "rtl/tiny/top/tiny_axi4_fabric.sv",
|
||||
"text": [
|
||||
"(s_selected_addr.len <= 8'd15)",
|
||||
"(s_last_addr[31:12] == s_selected_addr.addr[31:12])",
|
||||
"s_accept = (s_state_q == Idle) && s_selected_valid;",
|
||||
"Response: if (s_terminal) s_state_d = Idle;",
|
||||
"s_tgt_d = s_protocol_legal ? s_decoded_target : 3'd4;",
|
||||
"assign s_protocol_legal = !s_selected_addr.lock && (s_selected_addr.size <= 3'd2) &&\n ((s_selected_addr.addr & ((32'd1 << s_selected_addr.size) - 32'd1)) == 32'd0) &&\n ((s_selected_addr.burst == 2'b01) ||\n ((s_selected_addr.burst == 2'b00) && (s_selected_addr.len == 8'd0))) &&\n (s_selected_addr.len <= 8'd15) && !s_last_addr[32] &&\n (s_last_addr[31:12] == s_selected_addr.addr[31:12]) &&\n (decode_target(\n s_last_addr[31:0]\n ) == s_decoded_target) && ((s_decoded_target != 3'd2) || (s_selected_addr.len == 8'd0));",
|
||||
"assign s_terminal = (s_state_q == Response) &&\n (s_write_q ? (s_target_bvalid[s_tgt_q] && s_bready[s_owner_q]) :\n (s_target_rvalid[s_tgt_q] && s_rready[s_owner_q] && s_target_rlast[s_tgt_q]));"
|
||||
" function automatic logic [4:0] checked_target(\n input logic [31:0] addr_i, input logic [7:0] len_i,\n input logic [2:0] size_i, input logic [1:0] burst_i,\n input logic lock_i, input logic instruction_i);\n logic [32:0] last_addr;\n logic [4:0] decoded;\n decoded = decode_target(addr_i);\n last_addr = {1'b0, addr_i} + (({25'd0, len_i} + 33'd1) << size_i) - 33'd1;\n if (lock_i || (size_i > 3'd2) || (len_i > 8'd15) ||\n ((addr_i & ((32'd1 << size_i) - 32'd1)) != 32'd0) ||\n !((burst_i == 2'b01) || ((burst_i == 2'b00) && (len_i == 8'd0))) ||\n last_addr[32] || (last_addr[31:12] != addr_i[31:12]) ||\n (decode_target(last_addr[31:0]) != decoded) ||\n ((decoded >= 5'd5) && (decoded <= 5'd20) && (len_i != 8'd0)))\n return 5'd22;\n if (instruction_i && !(`SOC_ADDR_IS_FLASH(addr_i) ||\n ((addr_i >= 32'h5000_0000) && (addr_i < 32'h5400_0000))))\n return ((decoded >= 5'd5) && (decoded <= 5'd20)) ? 5'd22 : 5'd21;\n return decoded;\n endfunction",
|
||||
"assign s_busy_d = (s_busy_q & ~s_done) | s_admit;",
|
||||
"assign owner_idle_o[owner] = !(s_busy_q[2*owner] || s_busy_q[2*owner+1]);",
|
||||
"assign s_eligible[2*owner] = rst_n_i && owner_idle_o[owner] && masters[owner].arvalid && (!masters[owner].awvalid || !s_cpu_prefer_write_q);",
|
||||
"assign s_eligible[2*owner+1] = rst_n_i && owner_idle_o[owner] && masters[owner].awvalid && (!masters[owner].arvalid || s_cpu_prefer_write_q);"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -177,6 +182,20 @@
|
||||
"RS_DMA_CH_REG(channel, RS_DMA_CH_REG_TCD_COUNT) = UINT32_C(1);",
|
||||
"current = (rs_dma_tcd_t *)(uintptr_t)current->next_ptr;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "rtl/tiny/top/tiny_axi4_target.sv",
|
||||
"text": [
|
||||
"assign s_accept = (s_req_q.state == Idle) && enable_i && s_valid;",
|
||||
"assign s_terminal = s_resp_active && (s_req_q.write ? (s_b_valid && s_bready[s_req_q.owner]) : (s_r_valid && s_rready[s_req_q.owner] && s_r_data[1]));",
|
||||
"assign fault_valid_o = s_terminal && s_req_q.error_seen;",
|
||||
"if (!s_req_q.error_seen && (s_rin_data[3:2] != 2'b00)) begin s_req_d.error_seen = 1'b1; s_req_d.error_addr = s_req_q.read_addr; s_req_d.error_resp = s_rin_data[3:2]; end",
|
||||
"assign s_abort_write_valid = (s_req_q.state == AbortResponse) && s_req_q.write && s_req_q.write_done && !s_req_q.b_captured;",
|
||||
"assign s_abort_read_valid = (s_req_q.state == AbortResponse) && !s_req_q.write && (s_req_q.read_count <= {1'b0, s_saved_addr.len});",
|
||||
".flush_i(1'b0)",
|
||||
"AbortWrite: begin",
|
||||
"if (s_terminal) s_req_d.state = Idle;"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,6 +125,26 @@ def clean_source(text: str) -> str:
|
||||
return re.sub(r"\s+", "", re.sub(r"/\*.*?\*/|//[^\n]*", "", text, flags=re.S))
|
||||
|
||||
|
||||
def mini_channel_enum(text: str) -> str:
|
||||
"""Select Mini's channel roles, excluding the Tiny product branch.
|
||||
|
||||
Helper aliases share an allocated context; they do not allocate another
|
||||
channel. Keep their Mini bulk binding checked instead of parsing Tiny's
|
||||
literal 6/7 values from an inactive preprocessor branch.
|
||||
"""
|
||||
match = re.search(r"typedef enum\s*\{([^{}]*)\}\s*rs_dma_channel_t;", text, re.S)
|
||||
if match is None:
|
||||
raise ValueError("missing DMA channel enumeration")
|
||||
body = re.sub(r"#ifdef RS_SOC_TINY\s*\n[^#]*#else\s*\n([^#]*)#endif", r"\1", match[1])
|
||||
if "#" in body:
|
||||
raise ValueError("unreviewed Mini DMA channel selection")
|
||||
aliases = dict(re.findall(r"(RS_DMA_CHANNEL_\w+)\s*=\s*(RS_DMA_CHANNEL_\w+)\s*,", body))
|
||||
expected = {"RS_DMA_CHANNEL_DVP", "RS_DMA_CHANNEL_I2S_TX", "RS_DMA_CHANNEL_I2S_RX"}
|
||||
if any(name not in expected or value != "RS_DMA_CHANNEL_BULK" for name, value in aliases.items()):
|
||||
raise ValueError("Mini DMA helper alias binding changed")
|
||||
return body
|
||||
|
||||
|
||||
def validate_programming(spec: dict, ids: set[str], root: Path, revision: str) -> None:
|
||||
for relative in dependencies(spec):
|
||||
path = root / relative
|
||||
@@ -193,7 +213,7 @@ def collect_programming(root: Path, spec: dict, ids: set[str], revision: str) ->
|
||||
result = copy.deepcopy(spec)
|
||||
sdk_text = (root / "crt/include/retrosoc/hal/dma.h").read_text()
|
||||
sdk = constants(sdk_text, "RS_DMA_REQUEST_")
|
||||
channels = constants(sdk_text, "RS_DMA_CHANNEL_")
|
||||
channels = constants(mini_channel_enum(sdk_text), "RS_DMA_CHANNEL_")
|
||||
# Capacity is selected by product; it is not a named channel allocation.
|
||||
# Keep the Mini publication's role inventory independent of Tiny's count.
|
||||
channels.update(constants((root / "crt/include/retrosoc/hal/dma_regs.h").read_text(),
|
||||
|
||||
@@ -26,6 +26,9 @@ TOP = "rtl/tiny/top/retrosoc_tiny.sv"
|
||||
RESET_TREE = "rtl/tiny/top/tiny_reset_tree.sv"
|
||||
SYSCTRL = "rtl/tiny/top/tiny_sysctrl.sv"
|
||||
ARCHINFO = "rtl/tiny/top/tiny_archinfo.sv"
|
||||
CPU = "rtl/tiny/top/tiny_cpu_wrapper.sv"
|
||||
CPU_MEM = "rtl/tiny/top/tiny_cpu_mem.sv"
|
||||
SRAM = "rtl/tiny/top/tiny_sram.sv"
|
||||
FAMILIES = {"xpi", "sram", "gpio", "dma", "timer", "pwm", "rtc", "wdg", "uart", "i2c", "clint", "archinfo"}
|
||||
MANAGED = {"publication_media", "hazard3", "cluster_common", "cluster_archinfo", "cluster_pwm", "cluster_rtc", "cluster_wdg"}
|
||||
SUPPORTED_SYSCTRL = {
|
||||
@@ -65,21 +68,30 @@ def facts(root: Path = ROOT) -> dict:
|
||||
if any(profile.get(key) != value for key, value in required.items()):
|
||||
raise ValueError("Tiny publication profile changed; review configuration and ISA boundary")
|
||||
top = (root / TOP).read_text(encoding="utf-8")
|
||||
ram = instance_parameters(top, "onchip_ram", "u_sram")
|
||||
ram_reg = instance_parameters((root / SRAM).read_text(), "onchip_ram_reg", "u_reg")
|
||||
ram = {"CapacityKiB": ram_reg.get("CapacityKiB"),
|
||||
"DataWidth": 8 * ram_reg.get("DataBytes", 0), "IdWidth": 1}
|
||||
dma = instance_parameters(top, "apb4_dma", "u_dma")
|
||||
cpu = instance_parameters(top, "mgmt_core_wrapper", "u_cpu")
|
||||
if ram != {"CapacityKiB": 128, "DataWidth": 32, "IdWidth": 1, "Ics55SmallBanks": 1}:
|
||||
cpu = instance_parameters(top, "tiny_cpu_wrapper", "u_cpu")
|
||||
if ram != {"CapacityKiB": 128, "DataWidth": 32, "IdWidth": 1} or ram_reg.get("Present") != 1:
|
||||
raise ValueError("Tiny SRAM parameters changed")
|
||||
# The publication remains the reviewed IHP130 compatibility profile;
|
||||
# selecting ICS55's 4 KiB geometry does not alter its reported SRAM facts.
|
||||
ram = {key: value for key, value in ram.items() if key != "Ics55SmallBanks"}
|
||||
# P4 changes local routing, not physical geometry or the book's IHP130
|
||||
# compatibility selection. Snapshot enforcement still precedes publication.
|
||||
topology = read_topology(root / TOPOLOGY, root / MAP)
|
||||
require_snippets(root, TOP, ["tiny_sram u_sram", "gen_sram_attachment", "axi4_connector u_connector",
|
||||
".ID_WIDTH(1)", ".DATA_WIDTH(32)"])
|
||||
require_snippets(root, SRAM, ["group < 4", "tiny_sram_group u_group"])
|
||||
if dma != {"NumChannels": 4, "MaxBurstBeats": 16, "FifoDepth": 32, "RequestMask": 0x7F9, "EnableStreams": 0}:
|
||||
raise ValueError("Tiny DMA parameters changed")
|
||||
if cpu != {"ExternalIrqCount": 30, "EnableAtomics": 0, "TwoCycleBusErrors": 1, "ResetSyncStages": 5}:
|
||||
if cpu != {"ExternalIrqCount": 30, "EnableAtomics": 0, "ResetSyncStages": 5}:
|
||||
raise ValueError("Tiny CPU integration changed")
|
||||
require_snippets(root, RESET_TREE, [".STAGE(5)", "assign cpu_ready_rst_n_o = &leaf_rst_n_o;"])
|
||||
require_snippets(root, "rtl/ip/core/mgmt_core_wrapper.sv", [".EXTENSION_C(1)", ".EXTENSION_A(EnableAtomics)"])
|
||||
require_snippets(root, TOP, ["u_masters_axi4_if[2]", ".axi4(u_masters_axi4_if[0])",
|
||||
require_snippets(root, CPU, ["hazard3_cpu_2port", ".EXTENSION_C(1)", ".EXTENSION_A(EnableAtomics)"])
|
||||
require_snippets(root, CPU_MEM, [".TwoCycleErrors(1'b1)", "ErrorFirst", "ErrorLast"])
|
||||
require_snippets(root, TOP, ["u_masters_axi4_if[3]", "u_targets_axi4_if[23]",
|
||||
"assign u_masters_axi4_if[2].arvalid = 1'b0;",
|
||||
"assign u_masters_axi4_if[2].awvalid = 1'b0;",
|
||||
".slow_axi4(u_masters_axi4_if[0])",
|
||||
".axi4(u_masters_axi4_if[1])", ".cfg_apb4(u_sram_apb4_if)",
|
||||
"assign s_tick = s_tick_count_q == 5'd23;"])
|
||||
require_snippets(root, SYSCTRL, ["(apb4.paddr[1:0] != 2'd0)", "(apb4.pstrb != 4'hf)",
|
||||
@@ -99,6 +111,7 @@ def facts(root: Path = ROOT) -> dict:
|
||||
raise ValueError("Tiny discovery parameters changed")
|
||||
require_snippets(root, ARCHINFO, ["32'h5449_4e59 : u_info_apb4_if.prdata", ".device_id_valid_i(1'b0)", ".device_id_read_enable_i(1'b0)"])
|
||||
return {"profile": profile, "sram": ram, "dma": dma, "cpu": cpu, "archinfo": arch,
|
||||
"fabric": topology["fabric"],
|
||||
"hardware_isa": "RV32IMC", "firmware_isa": profile["ISA"], "soc_id": 0x54494E59,
|
||||
"system_hz": int(profile["EXT_CLK_HZ"]), "timebase_hz": int(profile["CLINT_TIMEBASE_HZ"])}
|
||||
|
||||
@@ -130,7 +143,7 @@ def sysctrl_registers(root: Path) -> dict:
|
||||
offsets = {r["symbol"]: int(r["offset"], 0) for r in read(root / MAP)["sysctrl_registers"]}
|
||||
definitions = {
|
||||
"FAULT_STATUS": ("RW1C", "Sticky first fault. Bit 0 clears pending; a new fault can win after clear.", [("PENDING", 0, 0, "A fault record is pending."), ("WRITE", 1, 1, "Faulting transaction was a write."), ("CLASS", 2, 4, "1: decode error; 2: protocol/target error.")]),
|
||||
"FAULT_MASTER": ("RO", "Master of the captured first fault.", [("MASTER", 0, 0, "0 CPU, 1 DMA.")]),
|
||||
"FAULT_MASTER": ("RO", "Master of the captured first fault.", [("MASTER", 0, 1, "0 CPU, 1 DMA, 2 reserved SDIO ingress; SDIO is not integrated.")]),
|
||||
"FAULT_DETAIL": ("RO", "Captured AXI response code.", [("RESPONSE", 0, 1, "AXI RRESP/BRESP encoding.")]),
|
||||
"PERF_CTRL": ("RW / command", "Enable counters, clear counters/snapshots or capture a coherent pair. Clear takes precedence over snapshot.", [("ENABLE", 0, 0, "Counter enable state."), ("CLEAR", 1, 1, "Write-one pulse; reads zero."), ("SNAPSHOT", 2, 2, "Write-one pulse; reads zero.")]),
|
||||
"TEST_STATUS": ("RW sticky", "First full-word valid result is sticky until system reset; write mask 0x8000FF01.", [("PASS", 0, 0, "Pass when valid is set."), ("CODE", 8, 15, "Application-defined result code."), ("VALID", 31, 31, "The first valid write locks the result.")]),
|
||||
|
||||
@@ -81,6 +81,7 @@ module mgmt_core_wrapper #(
|
||||
.jtag_trst_n_i(jtag_trst_n_i),
|
||||
.jtag_tdo_o(jtag_tdo_o),
|
||||
.core_rst_n_o(s_core_rst_n),
|
||||
.reset_pending_o(), // Mini retains its existing reset policy.
|
||||
.dbg_req_halt_o(s_dbg_req_halt),
|
||||
.dbg_req_halt_on_reset_o(s_dbg_req_halt_on_reset),
|
||||
.dbg_req_resume_o(s_dbg_req_resume),
|
||||
|
||||
@@ -19,12 +19,15 @@ module mgmt_debug_reset #(
|
||||
input logic reset_req_i,
|
||||
input logic bridge_idle_i,
|
||||
output logic core_rst_n_o,
|
||||
output logic reset_pending_o,
|
||||
output logic reset_done_o
|
||||
);
|
||||
|
||||
logic s_pending_d, s_pending_q;
|
||||
logic s_reset_active_d, s_reset_active_q;
|
||||
|
||||
assign reset_pending_o = reset_req_i || s_pending_q || s_reset_active_q;
|
||||
|
||||
always_comb begin
|
||||
s_pending_d = s_pending_q;
|
||||
s_reset_active_d = s_reset_active_q;
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
// management-core clock domain and exposes abstract commands only (no SBA).
|
||||
module mgmt_debug_wrapper #(
|
||||
parameter logic [31:0] JtagIdcode = 32'hDEAD_BEEF,
|
||||
parameter int ResetSyncStages = 3
|
||||
parameter int ResetSyncStages = 3,
|
||||
parameter bit SeparateSystemReset = 1'b0
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic system_rst_n_i,
|
||||
input logic bridge_idle_i,
|
||||
input logic jtag_tck_i,
|
||||
input logic jtag_tms_i,
|
||||
@@ -23,6 +25,7 @@ module mgmt_debug_wrapper #(
|
||||
input logic jtag_trst_n_i,
|
||||
output logic jtag_tdo_o,
|
||||
output logic core_rst_n_o,
|
||||
output logic reset_pending_o,
|
||||
|
||||
output logic dbg_req_halt_o,
|
||||
output logic dbg_req_halt_on_reset_o,
|
||||
@@ -155,10 +158,11 @@ module mgmt_debug_wrapper #(
|
||||
.ResetSyncStages(ResetSyncStages)
|
||||
) u_mgmt_debug_reset (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.rst_n_i (SeparateSystemReset ? system_rst_n_i : rst_n_i),
|
||||
.reset_req_i (s_sys_reset_req || s_hart_reset_req),
|
||||
.bridge_idle_i (bridge_idle_i),
|
||||
.core_rst_n_o (core_rst_n_o),
|
||||
.reset_pending_o(reset_pending_o),
|
||||
.reset_done_o (s_reset_done)
|
||||
);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ module apb4_dma #(
|
||||
parameter bit EnableStreams = 1'b1
|
||||
) (
|
||||
// verilog_format: off -- integration ports retain established peripheral endpoint names.
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
output logic dma_xfer_done_o,
|
||||
@@ -179,4 +180,7 @@ module apb4_dma #(
|
||||
.crypto_in_axis (crypto_in_axis),
|
||||
.crypto_out_axis (crypto_out_axis)
|
||||
);
|
||||
logic s_bus_busy;
|
||||
assign s_bus_busy = axi4.awvalid || axi4.arvalid || axi4.wvalid;
|
||||
assign lifecycle_idle_o = !(|s_busy) && !(|s_start) && !s_bus_busy;
|
||||
endmodule
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
module apb4_timer (
|
||||
// verilog_format: off -- preserve reviewed column alignment
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic debug_halted_i,
|
||||
@@ -89,4 +90,5 @@ module apb4_timer (
|
||||
.one_shot_done_o (s_one_shot_done)
|
||||
);
|
||||
|
||||
assign lifecycle_idle_o = !s_en;
|
||||
endmodule
|
||||
@@ -7,6 +7,7 @@ module apb4_crypto #(
|
||||
parameter logic [5:0] DropResponseMask = 6'd0,
|
||||
parameter bit DuplicateResponse = 1'b0
|
||||
) (
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
rst_n_i,
|
||||
output logic dma_input_proc_o,
|
||||
@@ -43,6 +44,10 @@ module apb4_crypto #(
|
||||
logic [11:0] s_offset;
|
||||
logic [31:0] s_wdata;
|
||||
logic [ 3:0] s_strb;
|
||||
logic s_transport_busy;
|
||||
assign s_transport_busy = (|s_fifo_busy) || (|s_engine_pending_q) || s_aes_key_busy;
|
||||
assign lifecycle_idle_o = !(|s_busy) && !s_maintenance_busy && !s_transport_busy;
|
||||
|
||||
assign s_offset = s_regs_q.offset;
|
||||
assign s_wdata = s_regs_q.data;
|
||||
assign s_strb = s_regs_q.mask;
|
||||
|
||||
@@ -13,6 +13,7 @@ module apb4_i2c #(
|
||||
parameter int RxFifoDepth = 16
|
||||
) (
|
||||
// verilog_format: off -- preserve reviewed column alignment
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
output logic dma_tx_stall_o,
|
||||
@@ -66,6 +67,8 @@ module apb4_i2c #(
|
||||
logic s_recovery_failed_event;
|
||||
logic s_core_cmd_flush;
|
||||
|
||||
assign lifecycle_idle_o = !s_en && !s_busy && !s_recovery_active;
|
||||
|
||||
assign i2c.scl_o = 1'b0;
|
||||
assign i2c.sda_o = 1'b0;
|
||||
assign i2c.scl_oe_o = s_scl_pull_low;
|
||||
|
||||
@@ -41,6 +41,8 @@ module apb4_i2s (
|
||||
output logic tx_underrun_evt_o,
|
||||
output logic rx_overrun_evt_o,
|
||||
output logic rx_flush_busy_o,
|
||||
output logic lifecycle_idle_o,
|
||||
output logic lifecycle_reset_ready_o,
|
||||
apb4_if.slave apb4,
|
||||
axi4_stream_if.sink tx_axis,
|
||||
axi4_stream_if.source rx_axis,
|
||||
@@ -120,6 +122,36 @@ module apb4_i2s (
|
||||
logic s_tx_underrun_sys;
|
||||
logic s_rx_overrun_sys;
|
||||
logic s_tx_flush_sent_d, s_tx_flush_sent_q;
|
||||
logic s_cfg_ready;
|
||||
logic [31:0] s_cfg_sent_d, s_cfg_sent_q;
|
||||
logic s_audio_used_d, s_audio_used_q;
|
||||
|
||||
// A disabled host which has never enabled its PHY may change host clock
|
||||
// even when AUDIO is absent. After use, require the disabled configuration
|
||||
// to reach AUDIO, empty FIFOs, and completed flush acknowledgements.
|
||||
assign s_cfg_sent_d = s_cfg_ready ? s_cfg_sys : s_cfg_sent_q;
|
||||
assign s_audio_used_d = s_audio_used_q || s_cfg_sys[`APB4_I2S__CFG_ENABLE];
|
||||
assign lifecycle_reset_ready_o = s_tx_src_ready && !s_tx_flush_busy && !s_rx_flush_busy;
|
||||
assign lifecycle_idle_o = !s_cfg_sys[`APB4_I2S__CFG_ENABLE] &&
|
||||
!s_stream_tx_en && !s_stream_rx_en &&
|
||||
(!s_audio_used_q || ((s_cfg_sent_q == s_cfg_sys) && s_cfg_ready &&
|
||||
s_tx_level == 0 && s_rx_level == 0 && !s_tx_flush_busy && !s_rx_flush_busy));
|
||||
dffr #(
|
||||
.DATA_WIDTH(32)
|
||||
) u_cfg_sent (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_cfg_sent_d),
|
||||
.dat_o (s_cfg_sent_q)
|
||||
);
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_audio_used (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_audio_used_d),
|
||||
.dat_o (s_audio_used_q)
|
||||
);
|
||||
|
||||
assign s_cmd_sys = {s_cmd_rx_flush, s_cmd_tx_flush};
|
||||
assign s_tx_src_clear = s_cmd_tx_flush && !s_tx_flush_sent_q && !s_tx_src_clear_busy;
|
||||
@@ -191,7 +223,7 @@ module apb4_i2s (
|
||||
.src_rst_n_i(rst_n_i),
|
||||
.src_data_i (s_cfg_sys),
|
||||
.src_valid_i(1'b1),
|
||||
.src_ready_o(),
|
||||
.src_ready_o(s_cfg_ready),
|
||||
.dst_clk_i (clk_aud_i),
|
||||
.dst_rst_n_i(rst_aud_n_i),
|
||||
.dst_data_o (s_cfg_aud),
|
||||
|
||||
@@ -13,6 +13,7 @@ module apb4_uart #(
|
||||
parameter int RxFifoDepth = 64
|
||||
) (
|
||||
// verilog_format: off -- preserve reviewed column alignment
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
output logic dma_tx_stall_o,
|
||||
@@ -53,6 +54,8 @@ module apb4_uart #(
|
||||
logic s_tx_flow_blocked;
|
||||
logic s_cts_change;
|
||||
|
||||
assign lifecycle_idle_o = !s_tx_busy && !s_rx_active && !s_tx_data_valid && !s_rx_en && !s_break;
|
||||
|
||||
assign uart.tx_o = s_tx;
|
||||
assign uart.irq_o = s_irq;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ module apb4_ws2812 #(
|
||||
parameter int TxFifoDepth = 16
|
||||
) (
|
||||
// verilog_format: off -- preserve reviewed column alignment
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
apb4_if.slave apb4,
|
||||
@@ -33,6 +34,8 @@ module apb4_ws2812 #(
|
||||
logic s_done, s_underflow, s_aborted;
|
||||
logic s_irq, s_dat;
|
||||
|
||||
assign lifecycle_idle_o = !s_busy && !s_reset_active && !s_start && !s_data_valid;
|
||||
|
||||
assign ws2812.dat_o = s_dat;
|
||||
assign ws2812.irq_o = s_irq;
|
||||
|
||||
|
||||
+13
-14
@@ -24,14 +24,14 @@ module i2s_recv (
|
||||
logic s_lrck_trg;
|
||||
logic [4:0] s_bit_cnt_d, s_bit_cnt_q;
|
||||
logic [4:0] s_bit_num;
|
||||
logic s_first_bit_d, s_first_bit_q;
|
||||
logic s_done_d, s_done_q;
|
||||
logic [23:0] s_recv_data_d, s_recv_data_q;
|
||||
logic [23:0] s_data_d, s_data_q;
|
||||
|
||||
|
||||
assign s_bit_num = bitmode_i ? 5'd23 : 5'd15;
|
||||
assign data_o = s_data_q;
|
||||
assign done_o = s_bit_cnt_q == s_bit_num;
|
||||
assign done_o = s_done_q;
|
||||
assign s_lrck_trg = lrck_i ^ s_lrck_dely_q;
|
||||
|
||||
|
||||
@@ -89,26 +89,25 @@ module i2s_recv (
|
||||
);
|
||||
|
||||
|
||||
always_comb begin
|
||||
s_first_bit_d = s_first_bit_q;
|
||||
if (s_lrck_trg) s_first_bit_d = adcdat_i;
|
||||
end
|
||||
dffer #(
|
||||
// I2S changes LRCK one bit before the next sample's MSB. The bit
|
||||
// sampled on that transition is the current sample's LSB, not the next
|
||||
// sample's first bit. Publish completion after data_o has captured it.
|
||||
assign s_done_d = sclk_pos_i && s_lrck_trg;
|
||||
dffr #(
|
||||
.DATA_WIDTH(1)
|
||||
) u_first_bit_dffer (
|
||||
) u_done_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (sclk_pos_i),
|
||||
.dat_i (s_first_bit_d),
|
||||
.dat_o (s_first_bit_q)
|
||||
.dat_i (s_done_d),
|
||||
.dat_o (s_done_q)
|
||||
);
|
||||
|
||||
|
||||
always_comb begin
|
||||
s_data_d = s_data_q;
|
||||
if ((!s_lrck_trg) && (s_bit_cnt_q == (s_bit_num - 1'b1))) begin
|
||||
if (bitmode_i) s_data_d = {s_recv_data_d[22:0], s_first_bit_q};
|
||||
else s_data_d = {8'd0, s_recv_data_d[14:0], s_first_bit_q};
|
||||
if (s_lrck_trg) begin
|
||||
if (bitmode_i) s_data_d = {s_recv_data_q[22:0], adcdat_i};
|
||||
else s_data_d = {8'd0, s_recv_data_q[14:0], adcdat_i};
|
||||
end
|
||||
end
|
||||
dffer #(
|
||||
|
||||
@@ -92,7 +92,7 @@ module i2s_reg (
|
||||
endfunction
|
||||
|
||||
assign s_req = apb4.psel && apb4.penable && !s_ready_q;
|
||||
assign s_write = |apb4.pstrb;
|
||||
assign s_write = apb4.pwrite;
|
||||
assign s_accept = s_req;
|
||||
assign s_offset = apb4.paddr[11:0];
|
||||
assign s_aligned = apb4.paddr[1:0] == 2'b00;
|
||||
|
||||
@@ -12,16 +12,19 @@
|
||||
|
||||
module apb4_sdio #(
|
||||
parameter int InputClockHz = 72_000_000,
|
||||
parameter bit UseRuntimeClockHz = 1'b0,
|
||||
parameter int AddrWidth = 32,
|
||||
parameter int DataWidth = 32,
|
||||
parameter int DescCount = 16
|
||||
) (
|
||||
// verilog_format: off -- preserve the APB, AXI, and pad column alignment
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
apb4_if.slave apb4,
|
||||
axi4_if.master dma_axi4,
|
||||
sdio_if.dut sdio
|
||||
sdio_if.dut sdio,
|
||||
input logic [31:0] clock_hz_i
|
||||
// verilog_format: on
|
||||
);
|
||||
logic s_busy;
|
||||
@@ -80,6 +83,10 @@ module apb4_sdio #(
|
||||
logic s_pio_read_consume;
|
||||
sdio_if u_sdio_core_if ();
|
||||
|
||||
logic s_bus_busy;
|
||||
assign s_bus_busy = dma_axi4.awvalid || dma_axi4.arvalid || dma_axi4.wvalid;
|
||||
assign lifecycle_idle_o = !s_busy && !s_clock_enable && !s_bus_busy;
|
||||
|
||||
assign u_sdio_core_if.cmd_di_i = sdio.cmd_di_i;
|
||||
assign u_sdio_core_if.dat_di_i = sdio.dat_di_i;
|
||||
assign sdio.sck_o = u_sdio_core_if.sck_o;
|
||||
@@ -150,6 +157,7 @@ module apb4_sdio #(
|
||||
|
||||
sdio_core #(
|
||||
.InputClockHz (InputClockHz),
|
||||
.UseRuntimeClockHz(UseRuntimeClockHz),
|
||||
.AddrWidth (AddrWidth),
|
||||
.DataWidth (DataWidth),
|
||||
.DescCount (DescCount)
|
||||
@@ -157,6 +165,7 @@ module apb4_sdio #(
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.host_enable_i (s_host_enable),
|
||||
.clock_hz_i (clock_hz_i),
|
||||
.host_irq_enable_i (s_host_irq_enable),
|
||||
.clock_enable_i (s_clock_enable),
|
||||
.half_period_i (s_half_period),
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
module apb4_xpi (
|
||||
// verilog_format: off -- preserve reviewed port alignment
|
||||
output logic lifecycle_idle_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic dma_xfer_done_i,
|
||||
@@ -176,6 +177,11 @@ module apb4_xpi (
|
||||
logic s_unused_dma_xfer_done;
|
||||
logic s_unused_mm_perf_split;
|
||||
|
||||
logic s_protocol_idle;
|
||||
assign s_protocol_idle = !s_mm_busy && !s_indirect_busy && !s_core_busy;
|
||||
assign lifecycle_idle_o = s_protocol_idle &&
|
||||
(s_owner_q == OwnerNone) && s_tx_fifo_empty && s_rx_fifo_empty;
|
||||
|
||||
assign s_owner_q = xpi_owner_e'(s_owner_bits_q);
|
||||
assign s_selected_req_valid = s_mm_busy ? s_mm_req_valid :
|
||||
(s_indirect_req_valid ? s_indirect_req_valid : s_mm_req_valid);
|
||||
|
||||
@@ -88,7 +88,10 @@ module sdio_command #(
|
||||
assign s_frame_crc_error = s_frame_crc != s_resp_shift_next[7:1];
|
||||
assign s_frame_index_error = s_resp_shift_next[45:40] != s_cmd_index_q;
|
||||
|
||||
assign cmd_oe_o = (s_state_q == Send) || (s_tx_final_hold_q && !sample_tick_i);
|
||||
// Admission can coincide with an SDCLK rising edge. Do not expose the
|
||||
// start bit until the first scheduled launch, or the card sees it twice.
|
||||
assign cmd_oe_o = ((s_state_q == Send) && (s_tx_started_q || launch_tick_i)) ||
|
||||
(s_tx_final_hold_q && !sample_tick_i);
|
||||
assign cmd_do_o = ((s_state_q == Send) || s_tx_final_hold_q) ? s_tx_shift_q[47] : 1'b1;
|
||||
assign busy_o = (s_state_q != Idle) && (s_state_q != Complete);
|
||||
assign done_o = s_done_q;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
module sdio_core #(
|
||||
parameter int InputClockHz = 72_000_000,
|
||||
parameter bit UseRuntimeClockHz = 1'b0,
|
||||
parameter int AddrWidth = 32,
|
||||
parameter int DataWidth = 32,
|
||||
parameter int DescCount = 16
|
||||
@@ -20,6 +21,7 @@ module sdio_core #(
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic host_enable_i,
|
||||
input logic [31:0] clock_hz_i,
|
||||
input logic host_irq_enable_i,
|
||||
input logic clock_enable_i,
|
||||
input logic [15:0] half_period_i,
|
||||
@@ -102,7 +104,7 @@ module sdio_core #(
|
||||
logic s_data_tx_last;
|
||||
logic s_data_rx_valid;
|
||||
logic s_data_rx_ready;
|
||||
logic s_data_rx_stall_q;
|
||||
logic s_data_rx_stall;
|
||||
logic [ 31:0] s_data_rx_data;
|
||||
logic [ 3:0] s_data_rx_strb;
|
||||
logic s_data_rx_last;
|
||||
@@ -174,8 +176,8 @@ module sdio_core #(
|
||||
assign s_clock_en = host_enable_i && clock_enable_i &&
|
||||
(s_cmd_busy || s_data_busy || s_dma_busy || cmd_start_i ||
|
||||
data_start_i) &&
|
||||
!s_data_rx_stall_q &&
|
||||
!(s_data_busy && s_data_tx_wait && (s_data_oe == 4'b0000));
|
||||
!s_data_rx_stall &&
|
||||
!(s_data_busy && s_data_tx_wait);
|
||||
assign s_total_bytes = {16'd0, block_size_i} * {16'd0, block_count_i};
|
||||
assign s_abort_request = host_abort_i || dma_abort_i ||
|
||||
(s_dma_done && s_dma_err) ||
|
||||
@@ -200,6 +202,9 @@ module sdio_core #(
|
||||
assign s_dma_data_in_strb = s_data_rx_strb;
|
||||
assign s_dma_data_in_last = s_data_rx_last;
|
||||
assign s_data_rx_ready = data_dma_enable_i ? s_dma_data_in_ready : !s_pio_valid_q;
|
||||
// ReadEmit begins on the sampling edge. Stop before the very next launch
|
||||
// if its word cannot retire; registering this condition loses one card bit.
|
||||
assign s_data_rx_stall = s_data_rx_valid && !s_data_rx_ready;
|
||||
assign s_core_busy = s_cmd_busy || s_data_busy || s_dma_busy;
|
||||
assign busy_o = s_core_busy;
|
||||
assign s_pio_tx_pop = !data_dma_enable_i && s_data_tx_valid && s_data_tx_ready;
|
||||
@@ -233,7 +238,9 @@ module sdio_core #(
|
||||
assign bytes_done_o = s_dma_bytes_done;
|
||||
assign dma_error_addr_o = s_dma_err_addr;
|
||||
assign dma_error_o = {24'd0, s_dma_err_code};
|
||||
assign clock_actual_o = (half_period_i == 16'd0) ? 32'd0 : InputClockHz / (2 * half_period_i);
|
||||
logic [31:0] s_input_clock_hz;
|
||||
assign s_input_clock_hz = UseRuntimeClockHz && (clock_hz_i != 32'd0) ? clock_hz_i : InputClockHz;
|
||||
assign clock_actual_o = (half_period_i == 16'd0) ? 32'd0 : s_input_clock_hz / (2 * half_period_i);
|
||||
assign status_o = {
|
||||
23'd0,
|
||||
s_clock_running,
|
||||
@@ -401,7 +408,6 @@ module sdio_core #(
|
||||
s_dat1_meta_q <= 1'b1;
|
||||
s_dat1_sync_q <= 1'b1;
|
||||
s_dat1_seen_q <= 1'b0;
|
||||
s_data_rx_stall_q <= 1'b0;
|
||||
s_pio_rdata_q <= '0;
|
||||
s_pio_valid_q <= 1'b0;
|
||||
s_pio_tx_rd_q <= '0;
|
||||
@@ -421,7 +427,6 @@ module sdio_core #(
|
||||
s_dat1_meta_q <= sdio.dat_di_i[1];
|
||||
s_dat1_sync_q <= s_dat1_meta_q;
|
||||
s_dat1_seen_q <= s_dat1_seen_d;
|
||||
s_data_rx_stall_q <= s_data_rx_valid && !s_data_rx_ready;
|
||||
|
||||
if (data_start_i) begin
|
||||
s_pio_tx_rd_q <= '0;
|
||||
|
||||
@@ -160,7 +160,12 @@ module sdio_data #(
|
||||
assign tx_ready_o = (s_state_q == WriteWaitWord) || (s_state_q == WriteNextWord) ||
|
||||
((s_state_q == WritePayload) && launch_tick_i && s_tx_word_final &&
|
||||
(s_tx_total_q < s_target_bytes_q));
|
||||
assign tx_wait_o = (s_state_q == WriteWaitWord) || (s_state_q == WriteNextWord);
|
||||
// Stop before launching the next word if memory has not supplied it.
|
||||
// Waiting only after that launch exposes an idle bit to the card and
|
||||
// corrupts the next word's MSB when the clock resumes.
|
||||
assign tx_wait_o = (s_state_q == WriteWaitWord) || (s_state_q == WriteNextWord) ||
|
||||
((s_state_q == WritePayload) && s_tx_word_final &&
|
||||
(s_tx_total_q < s_target_bytes_q) && !tx_valid_i);
|
||||
assign rx_valid_o = (s_state_q == ReadEmit);
|
||||
assign rx_data_o = s_rx_pending_data_q;
|
||||
assign rx_strb_o = s_rx_pending_strb_q;
|
||||
|
||||
@@ -516,11 +516,18 @@ module sdio_dma #(
|
||||
s_err_addr_d = s_payload_addr + s_burst_offset;
|
||||
end
|
||||
if (s_write_final_sent_q) begin
|
||||
// A retired AXI burst is not necessarily the whole descriptor.
|
||||
// Keep ownership while subsequent bursts receive its remaining
|
||||
// bytes, just as the memory-to-card direction does.
|
||||
if (s_fault_d || (s_desc_progress_d >= s_desc_count_q)) begin
|
||||
s_writeback_control_d = (s_desc_control_q &
|
||||
~(32'd1 << sdio_pkg::SDIO_DESC_OWN)) |
|
||||
(s_fault_d ? (32'd1 << sdio_pkg::SDIO_DESC_ERROR) :
|
||||
(32'd1 << sdio_pkg::SDIO_DESC_DONE));
|
||||
s_state_d = WritebackStart;
|
||||
end else begin
|
||||
s_state_d = PayloadWriteStart;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+6
-4
@@ -123,6 +123,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/clint.c \
|
||||
$(ROOT_PATH)/crt/src/hal/clock.c \
|
||||
$(ROOT_PATH)/crt/src/hal/sysctrl.c \
|
||||
$(ROOT_PATH)/crt/src/hal/rcu.c \
|
||||
$(ROOT_PATH)/crt/src/hal/uart_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/uart.c \
|
||||
$(ROOT_PATH)/crt/src/hal/gpio_math.c \
|
||||
@@ -182,7 +183,8 @@ CFLAGS += -DRS_SOC_TINY
|
||||
TINY_CRT_NAMES := startup.S clzsi2.c divdi3.c ffssi2.c udivdi3.c umoddi3.c \
|
||||
stdlib.c string.c console.c printf.c archinfo.c clint.c uart_math.c uart.c \
|
||||
gpio_math.c gpio.c timer_math.c timer.c pwm.c rtc.c wdg.c watchdog.c i2c_math.c i2c.c \
|
||||
dma_math.c dma.c onchip_sram.c xpi.c
|
||||
dma_math.c dma.c onchip_sram.c xpi.c rng.c crc.c ws2812_math.c ws2812.c \
|
||||
crypto.c crypto_lifecycle.c i2s_math.c i2s.c sdio_math.c sdio.c rcu.c
|
||||
CRT_SRCS := $(foreach source,$(CRT_SRCS),$(if $(filter $(notdir $(source)),$(TINY_CRT_NAMES)),$(source)))
|
||||
CRT_SRCS += $(ROOT_PATH)/crt/src/hal/sysctrl.c
|
||||
endif
|
||||
@@ -285,12 +287,12 @@ asm: $(MPW_VARIANT_DEP) $(MEMORY_MAP_STAMP)
|
||||
cp $(SW_BUILD_DIR)/asm/hello-asm.bin $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME).bin
|
||||
cp $(SW_BUILD_DIR)/asm/hello-asm.txt $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME)_all.txt
|
||||
|
||||
endif
|
||||
|
||||
$(CRYPTO_CONSTANTS_HEADER): $(ROOT_PATH)/scripts/crypto_constants.py $(ROOT_PATH)/scripts/data/crypto_constants.json
|
||||
$(PYTHON) $(ROOT_PATH)/scripts/crypto_constants.py --root $(ROOT_PATH) --output $(SW_BUILD_DIR)/include
|
||||
|
||||
endif
|
||||
|
||||
CRYPTO_CONSTANTS_DEP := $(if $(filter TINY,$(SOC)),,$(CRYPTO_CONSTANTS_HEADER))
|
||||
CRYPTO_CONSTANTS_DEP := $(CRYPTO_CONSTANTS_HEADER)
|
||||
|
||||
$(FIRMWARE_ELF): $(MPW_VARIANT_DEP) $(MEMORY_MAP_STAMP) $(SOC_TOPOLOGY_STAMP) $(SOC_IRQ_METADATA) $(USER_EXTENSIONS_STAMP) $(ARCHINFO_METADATA_STAMP) $(VERSION_HEADER) $(CRYPTO_CONSTANTS_DEP) $(SRC_PATH) $(SW_HEADERS) $(LDS_PATH) \
|
||||
$(ROOT_PATH)/rtl/mk/software.mk $(APP_MK)
|
||||
|
||||
@@ -1,6 +1,40 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"targets": [
|
||||
{
|
||||
"name": "tiny-r2-p5",
|
||||
"paths": ["rtl/tiny/top"],
|
||||
"status": "prototype",
|
||||
"baseline_revision": "3131762b35e0ebfcd196395f955e7c1005bd18e7",
|
||||
"configuration_digest": null,
|
||||
"configuration_profiles": ["configs/ci/ics55-tiny.mk", "configs/ci/ihp130-tiny.mk"],
|
||||
"required_evidence": [],
|
||||
"synthesis_intent": {
|
||||
"registers": "Common registers and bounded response spill registers per external target",
|
||||
"reset": "accepted CPU work drains before hart reset; system reset invalidates all sessions",
|
||||
"clock_enable": "all fabric, APB, CPU and SRAM logic remains on direct SAFE24 SYS",
|
||||
"memory": "unchanged 32 SRAM macros; no global SRAM transaction lock",
|
||||
"pipeline": "one combined transaction per target, CPU one combined, DMA/SDIO one per direction"
|
||||
},
|
||||
"waivers": []
|
||||
},
|
||||
{
|
||||
"name": "tiny-r2-p4",
|
||||
"paths": ["rtl/tiny/top"],
|
||||
"status": "prototype",
|
||||
"baseline_revision": "4db27524a6282ca40d76b935415b89f043d6ea83",
|
||||
"configuration_digest": null,
|
||||
"configuration_profiles": ["configs/ci/ics55-tiny.mk", "configs/ci/ihp130-tiny.mk"],
|
||||
"required_evidence": [],
|
||||
"synthesis_intent": {
|
||||
"registers": "Common registers; independent I/D request state and per-group responses",
|
||||
"reset": "five-edge release; hart halt/drain leaves SRAM and unrelated DMA active",
|
||||
"clock_enable": "CPU and all 32 main-SRAM macros use direct SAFE24 SYS",
|
||||
"memory": "four groups of eight tc_sram_1024x32 macros; no payload reset or extra SRAM",
|
||||
"pipeline": "AHB capture, macro issue, registered response; uncontended completion within three cycles"
|
||||
},
|
||||
"waivers": []
|
||||
},
|
||||
{
|
||||
"name": "owned-rtl",
|
||||
"paths": [
|
||||
|
||||
@@ -439,8 +439,26 @@
|
||||
"tiny_archinfo.sv",
|
||||
"tiny_axi42apb4.sv",
|
||||
"tiny_axi4_fabric.sv",
|
||||
"tiny_axi4_target.sv",
|
||||
"tiny_cpu_mem.sv",
|
||||
"tiny_cpu_wrapper.sv",
|
||||
"tiny_fault_collector.sv",
|
||||
"tiny_clock_reset_subsystem.sv",
|
||||
"tiny_axi4_async_bridge.sv",
|
||||
"tiny_apb_async_bridge.sv",
|
||||
"tiny_axi4_admission.sv",
|
||||
"tiny_managed_lifecycle.sv",
|
||||
"tiny_peripheral_leaf.sv",
|
||||
"tiny_peripheral_control.sv",
|
||||
"tiny_clock_output.sv",
|
||||
"tiny_clock_gate.sv",
|
||||
"tiny_reset_tree.sv",
|
||||
"tiny_sysctrl.sv"
|
||||
"tiny_sram.sv",
|
||||
"tiny_sram_axi4.sv",
|
||||
"tiny_sram_group.sv",
|
||||
"tiny_sram_port_if.sv",
|
||||
"tiny_sysctrl.sv",
|
||||
"tiny_rcu_regs.svh"
|
||||
]
|
||||
},
|
||||
"reviewed_boundaries": [
|
||||
|
||||
+6
-5
@@ -8,6 +8,7 @@
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
module tc_pll #(
|
||||
parameter bit UseIcs55EcosPll = 1'b0,
|
||||
parameter bit Ics55Parked = 1'b0
|
||||
@@ -30,8 +31,8 @@ module tc_pll #(
|
||||
logic s_apply_seen_d, s_apply_seen_q;
|
||||
logic s_cfg_apply;
|
||||
logic s_force_lock_fail;
|
||||
time s_last_ref_edge;
|
||||
time s_ref_period;
|
||||
realtime s_last_ref_edge;
|
||||
realtime s_ref_period;
|
||||
|
||||
function automatic int pll_multiplier(input logic [2:0] cfg_sel);
|
||||
case (cfg_sel)
|
||||
@@ -55,14 +56,14 @@ module tc_pll #(
|
||||
|
||||
always @(posedge fref_i) begin
|
||||
if (s_last_ref_edge != 0) begin
|
||||
s_ref_period = $time - s_last_ref_edge;
|
||||
s_ref_period = $realtime - s_last_ref_edge;
|
||||
end
|
||||
s_last_ref_edge = $time;
|
||||
s_last_ref_edge = $realtime;
|
||||
end
|
||||
|
||||
always begin
|
||||
@(posedge fref_i);
|
||||
wait (pll_lock_o);
|
||||
wait (pll_lock_o && s_ref_period > 0.0);
|
||||
while (pll_lock_o) begin
|
||||
#(s_ref_period / (2 * pll_multiplier(s_cfg_sel_q)));
|
||||
if (pll_lock_o) begin
|
||||
|
||||
+36
-1
@@ -60,6 +60,7 @@ OPENSTA_CONFIG := $(SYN_BUILD_ROOT)/out/$(RTL_NAME)_yosys.config
|
||||
NETLIST_PATH := $(OPENSTA_NETLIST)
|
||||
TINY_CONVERTED := $(SIM_BUILD_ROOT)/converted_soc.v
|
||||
TINY_DEPFILE := $(SIM_BUILD_ROOT)/sources.d
|
||||
TINY_TB_DEPFILE := $(SIM_BUILD_ROOT)/testbench.d
|
||||
TINY_LINT_LOG := $(VARIANT_ROOT)/lint/verilator/lint.log
|
||||
SOC_SIM_TIME ?= 1800
|
||||
TINY_SIM_TIMEOUT ?= 20000000
|
||||
@@ -69,7 +70,7 @@ IVERILOG ?= iverilog
|
||||
VVP ?= vvp
|
||||
|
||||
include $(ROOT_PATH)/rtl/mk/software.mk
|
||||
-include $(TINY_DEPFILE)
|
||||
-include $(TINY_DEPFILE) $(TINY_TB_DEPFILE)
|
||||
|
||||
$(TINY_CONVERTED): $(FILELIST_STAMP)
|
||||
@mkdir -p $(@D)
|
||||
@@ -95,6 +96,9 @@ $(SIM_BUILD_ROOT)/simv: $(TINY_CONVERTED) $(wildcard $(RTL_PATH)/dv/*.sv)
|
||||
--log $(SIM_BUILD_ROOT)/compile.log --result $(SIM_BUILD_ROOT)/result-compile.json -- \
|
||||
$(IVERILOG) -g2012 -gno-specify -s $(RTL_TOP) -o $@ -f $(GENERATED_FL_DIR)/def.fl \
|
||||
-f $(GENERATED_FL_DIR)/inc.fl -f $(PDK_FILELIST) $(TINY_TB_FLIST) $(TINY_CONVERTED)
|
||||
$(PYTHON) $(ROOT_PATH)/scripts/rtl/filelist_deps.py -f $(GENERATED_FL_DIR)/def.fl \
|
||||
-f $(GENERATED_FL_DIR)/inc.fl $(TINY_TB_FLIST) \
|
||||
--target $@ --output $(TINY_TB_DEPFILE)
|
||||
comp: $(SIM_BUILD_ROOT)/simv
|
||||
TINY_RUN := $(VVP) $(SIM_BUILD_ROOT)/simv
|
||||
endif
|
||||
@@ -201,3 +205,34 @@ tiny-r2-p3-report:
|
||||
$(PYTHON) $(TINY_P3_TOOL) --root $(ROOT_PATH) --variant-root $(VARIANT_ROOT) report
|
||||
|
||||
.PHONY: tiny-r2-p3-image tiny-r2-p3-sim tiny-r2-p3-matrix tiny-r2-p3-report
|
||||
|
||||
# P4 preserves old image identity and replays each selected image exactly once.
|
||||
TINY_P4_REFERENCE ?=
|
||||
TINY_P4_CASES ?= perf-o2-plain-flat,perf-o2-plain-banked
|
||||
tiny-r2-p4-replay: | manifest
|
||||
$(PYTHON) $(ROOT_PATH)/scripts/tiny_r2_p4.py --root $(ROOT_PATH) --variant-root $(VARIANT_ROOT) \
|
||||
--reference $(TINY_P4_REFERENCE) --cases $(TINY_P4_CASES) --simulator $(SIM_TOOL_NAME) \
|
||||
--vvp $(VVP) --timeout $(SOC_SIM_TIME) -- \
|
||||
make --no-print-directory -j1 -B CONFIG=$(CONFIG_PATH) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
||||
$(foreach var,$(CONFIG_KEY_VARS),$(var)=$($(var))) SIMU=$(SIMU) SYNTH=NONE STA=NONE comp
|
||||
|
||||
tiny-r2-p4-report:
|
||||
$(PYTHON) $(ROOT_PATH)/scripts/tiny_r2_p4.py --root $(ROOT_PATH) --variant-root $(VARIANT_ROOT) --report
|
||||
|
||||
.PHONY: tiny-r2-p4-replay tiny-r2-p4-report
|
||||
|
||||
# P5 compares the same P3 binaries to retained P4 observations, with its own
|
||||
# phase identity and evidence root. The historical P3/P4 commands stay intact.
|
||||
TINY_P5_REFERENCE ?=
|
||||
TINY_P5_CASES ?= perf-o2-plain-flat,perf-o2-plain-banked
|
||||
tiny-r2-p5-replay: | manifest
|
||||
$(PYTHON) $(ROOT_PATH)/scripts/tiny_r2_p5.py --root $(ROOT_PATH) --variant-root $(VARIANT_ROOT) \
|
||||
--reference $(TINY_P5_REFERENCE) --cases $(TINY_P5_CASES) --simulator $(SIM_TOOL_NAME) \
|
||||
--vvp $(VVP) --timeout $(SOC_SIM_TIME) -- \
|
||||
make --no-print-directory -j1 -B CONFIG=$(CONFIG_PATH) BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
|
||||
$(foreach var,$(CONFIG_KEY_VARS),$(var)=$($(var))) SIMU=$(SIMU) SYNTH=NONE STA=NONE comp
|
||||
|
||||
tiny-r2-p5-report:
|
||||
$(PYTHON) $(ROOT_PATH)/scripts/tiny_r2_p5.py --root $(ROOT_PATH) --variant-root $(VARIANT_ROOT) --report
|
||||
|
||||
.PHONY: tiny-r2-p5-replay tiny-r2-p5-report
|
||||
+18
-5
@@ -7,7 +7,20 @@ Use `make CONFIG=configs/ci/ics55-tiny.mk setup` followed by
|
||||
`make CONFIG=configs/ci/ics55-tiny.mk firmware sim`. IHP130/no PLL remains
|
||||
explicit compatibility through `configs/ci/ihp130-tiny.mk`. See the
|
||||
[platform runbook](../../docs/ip/tiny-ics55-platform.md) for source-bound
|
||||
validation; backend frequency tests are not SYS switching or timing qualification.
|
||||
validation of the historical SAFE24 platform. The
|
||||
[R2-P7 runbook](../../docs/ip/tiny-soc-r2-clock-reset.md) describes the integrated
|
||||
RCU, runtime domains and separate acceptance evidence. Backend frequency tests
|
||||
alone are not full-SoC or physical qualification.
|
||||
|
||||
The [R2-P4 implementation](../../docs/ip/tiny-soc-r2-local-memory.md) connects the
|
||||
official dual-port CPU to four independently serviced 32 KiB local SRAM groups.
|
||||
The 32 physical macros and register ABI are unchanged. Only non-SRAM CPU work
|
||||
uses the tagged slow path. The [P5 implementation](../../docs/ip/tiny-soc-r2-concurrent-fabric.md)
|
||||
replaces external serialization with independent target ownership and APB
|
||||
branches. The [P6 candidate](../../docs/ip/tiny-soc-r2-shared-integration.md)
|
||||
activates the SDIO ingress, eight-channel DMA, RNG/CRC/WS2812/Crypto and the
|
||||
existing I2S master path. Its validation and acceptance remain in the ledger.
|
||||
Source presence alone is not completed phase or physical qualification.
|
||||
|
||||
`top` owns product integration, `address_map`, `pin_map` and `integration` own
|
||||
canonical address, pad, IRQ and clock/reset inputs, `filelist` selects sources,
|
||||
@@ -43,8 +56,8 @@ final timing closure is mandatory. Software/DMA scheduling is `TINY-R2-P3`, loca
|
||||
`TINY-R2-P9`, system qualification `TINY-R2-P10` and complete-product physical
|
||||
qualification `TINY-R2-P11` (historical IHP130 title; now default ICS55).
|
||||
Legacy `TINY-P0` through `TINY-P12` remain in
|
||||
the contract history. The committed RTL/profile still implements the initial
|
||||
24 MHz/no-PLL/four-channel design; no faster CPU/SRAM or PLL timing support
|
||||
the contract history. The P6 candidate retains SAFE24 with eight DMA channels;
|
||||
ICS55's present PLL stays off. No faster CPU/SRAM or PLL timing support
|
||||
follows from this freeze or the `HAVE_PLL` selector alone.
|
||||
|
||||
The R2-P2 candidate keeps that executable clock/memory configuration and adds
|
||||
@@ -88,8 +101,8 @@ FIFOs, APB4 `0x1001D000..0x1001DFFF`, IRQ25 and RCU target16. DMA V2.2 adds
|
||||
paced fixed-MMIO requests `SPI_TX=16` / `SPI_RX=17`; payload MMIO retains
|
||||
single-beat transactions. TX borrows channel3 and RX channel2 only after
|
||||
prior owners fully drain and release them. No extra AXI master, DMA channel,
|
||||
SRAM capacity or pad is added. None of these paths exists in the current
|
||||
24 MHz/no-PLL/four-channel RTL/profile.
|
||||
SRAM capacity or pad is added. SPI and its requests remain absent from the
|
||||
SAFE24 P6 candidate.
|
||||
|
||||
The frozen Gen1 routes add only GPIO27 ALT0 SCK, GPIO28 ALT1 MOSI, GPIO30
|
||||
ALT1 MISO and GPIO31 ALT1 CS_N. Write-only display mode uses ordinary GPIO30
|
||||
|
||||
@@ -300,15 +300,6 @@
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_I2C1",
|
||||
"base": "0x10011000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "rw"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_GPIO_ADMIN",
|
||||
"base": "0x10014000",
|
||||
@@ -327,15 +318,6 @@
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_UART1",
|
||||
"base": "0x10018000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "rw"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_ARCHINFO",
|
||||
"base": "0x20000000",
|
||||
@@ -399,6 +381,60 @@
|
||||
"public": true,
|
||||
"user_access": "rw",
|
||||
"burst": "incr16"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_RNG",
|
||||
"base": "0x20001000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_system",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_CRC",
|
||||
"base": "0x20006000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_system",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_WS2812",
|
||||
"base": "0x10008000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_CRYPTO",
|
||||
"base": "0x1000C000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_I2S",
|
||||
"base": "0x10007000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
},
|
||||
{
|
||||
"symbol": "APB4_SDIO0",
|
||||
"base": "0x1000F000",
|
||||
"size": "0x00001000",
|
||||
"route": "apb4_periph",
|
||||
"kind": "active",
|
||||
"public": true,
|
||||
"user_access": "none"
|
||||
}
|
||||
],
|
||||
"legacy_rib": false,
|
||||
|
||||
+185
-57
@@ -1,3 +1,4 @@
|
||||
`include "tiny_topology.svh"
|
||||
// Copyright (c) 2026 Yuchi Miao
|
||||
// SPDX-License-Identifier: MulanPSL-2.0
|
||||
`timescale 1ns / 1ps
|
||||
@@ -5,7 +6,10 @@
|
||||
module retrosoc_tiny_tb;
|
||||
logic s_clk_driver = 1'b0;
|
||||
wire s_clk = s_clk_driver;
|
||||
logic s_reset_driver = 1'b0;
|
||||
// Assert RESET_N after time zero. With a divided REF24 there are no REF
|
||||
// edges while reset is held, so a declaration initialized low is not an
|
||||
// observable asynchronous assertion for every four-state simulator process.
|
||||
logic s_reset_driver = $test$plusargs("p7_legacy_reset_level") ? 1'b0 : 1'b1;
|
||||
wire s_rst_n = s_reset_driver;
|
||||
wire s_uart0_tx, s_uart1_tx;
|
||||
wire s_uart0_rx = 1'b1;
|
||||
@@ -18,11 +22,15 @@ module retrosoc_tiny_tb;
|
||||
wire s_jtag_tdi = s_jtag_tdi_driver;
|
||||
wire s_jtag_trst_n = s_rst_n;
|
||||
wire s_jtag_tdo;
|
||||
tri1 [31:0] s_gpio;
|
||||
`include "tiny_tb_gpio.svh"
|
||||
wire s_xpi_sck;
|
||||
wire [3:0] s_xpi_nss;
|
||||
tri [3:0] s_xpi_data;
|
||||
integer s_cycles;
|
||||
`ifndef RETROSOC_SOC__TINY_NETLIST
|
||||
`include "tiny_p6_devices.svh"
|
||||
`include "tiny_p7_observers.svh"
|
||||
`endif
|
||||
integer s_max_cycles = 20000000;
|
||||
integer s_done_cycles = 0;
|
||||
logic [7:0] s_uart_byte;
|
||||
@@ -43,8 +51,12 @@ module retrosoc_tiny_tb;
|
||||
wire [7:0] s_test_code = u_dut.s_test_code;
|
||||
`endif
|
||||
|
||||
always #20.833333 s_clk_driver = !s_clk_driver;
|
||||
always #(500000000.0 / `SOC_EXT_CLK_HZ) s_clk_driver = !s_clk_driver;
|
||||
initial begin
|
||||
if (!$test$plusargs("p7_legacy_reset_level")) begin
|
||||
#1;
|
||||
s_reset_driver = 1'b0;
|
||||
end
|
||||
if ($value$plusargs("max_cycles=%d", s_max_cycles)) begin
|
||||
end
|
||||
repeat (20) @(posedge s_clk);
|
||||
@@ -53,7 +65,8 @@ module retrosoc_tiny_tb;
|
||||
for (s_cycles = 0; s_cycles < s_max_cycles; s_cycles = s_cycles + 1) begin
|
||||
@(posedge s_clk);
|
||||
if (u_dut.s_test_done) begin
|
||||
if (!u_dut.s_test_pass) $fatal(1, "SIM_TEST_FAIL code=%0d", s_test_code);
|
||||
if (u_dut.s_test_pass !== 1'b1 || (^s_test_code) === 1'bx)
|
||||
$fatal(1, "SIM_TEST_FAIL code=%0d", s_test_code);
|
||||
s_done_cycles = s_done_cycles + 1;
|
||||
if (s_done_cycles >= 128 && s_jtag_checks_done) begin
|
||||
$display("SIM_TEST_PASS Tiny cycles=%0d", s_cycles);
|
||||
@@ -64,24 +77,15 @@ module retrosoc_tiny_tb;
|
||||
if (s_done_cycles != 128) $fatal(1, "SIM_TEST_TIMEOUT Tiny cycles=%0d", s_cycles);
|
||||
end
|
||||
|
||||
`ifdef RETROSOC_SOC__TINY_NETLIST
|
||||
`ifdef SIMU_IVERILOG
|
||||
localparam bit ObserveUartAlways = 1'b1;
|
||||
`else
|
||||
localparam bit ObserveUartAlways = 1'b0;
|
||||
`endif
|
||||
`ifdef SIMU_IVERILOG
|
||||
localparam bit ObserveUartBaseline = 1'b1;
|
||||
`else
|
||||
localparam bit ObserveUartBaseline = 1'b0;
|
||||
`endif
|
||||
// The Verilator RTL already prints accepted TX bytes. The Icarus observer is
|
||||
// opt-in for measurements; SYSCTRL remains the authoritative verdict.
|
||||
// The Verilator RTL prints accepted TX bytes. Icarus observes serial output for
|
||||
// all firmware measurements; SYSCTRL remains the authoritative verdict.
|
||||
initial begin
|
||||
if (ObserveUartAlways || (ObserveUartBaseline && ($test$plusargs(
|
||||
"tiny_r2_baseline"
|
||||
) || $test$plusargs(
|
||||
"tiny_r2_p3"
|
||||
)))) begin
|
||||
if (ObserveUartAlways) begin
|
||||
forever begin
|
||||
@(negedge s_uart0_tx);
|
||||
#1627.604;
|
||||
@@ -230,57 +234,181 @@ module retrosoc_tiny_tb;
|
||||
`undef _BASELINE_AXI
|
||||
end
|
||||
|
||||
// The baseline has one AHB port. HPROT[0] distinguishes instruction/data;
|
||||
// these observations do not assert future independent local-I/D latency.
|
||||
longint unsigned s_ahb_cycle = 0;
|
||||
longint unsigned s_ahb_start = 0;
|
||||
longint unsigned s_ahb_accept[2], s_ahb_done[2], s_ahb_latency[2];
|
||||
logic s_ahb_pending = 1'b0, s_ahb_measured = 1'b0;
|
||||
logic s_ahb_data = 1'b0, s_ahb_previous_enable = 1'b0;
|
||||
integer s_ahb_window = 0;
|
||||
wire s_ahb_enable = u_dut.u_soc.s_perf_enable && s_baseline_enabled;
|
||||
`define _BASELINE_AHB u_dut.u_soc.u_cpu.u_ahbl_if
|
||||
// P5-only observations supplement the unchanged P3/P4 record formats. They
|
||||
// are testbench measurements, not new software-visible performance counters.
|
||||
longint unsigned s_p5_overlap = 0, s_p5_beat_overlap = 0;
|
||||
integer s_p5_window = 0, s_p5_active_max = 0;
|
||||
logic s_p5_previous_enable = 0;
|
||||
wire s_p5_enable = s_baseline_enabled && u_dut.u_soc.s_perf_enable;
|
||||
// Icarus 13 miscounts the temporary expression $countones(~a_23_bit_vector).
|
||||
// Count declared bits explicitly and reject unknowns rather than correcting
|
||||
// a report afterward. This function changes only opt-in P5 observations.
|
||||
function automatic integer p5_active_targets(
|
||||
input logic [`RETROSOC_TINY__TARGET_COUNT-1:0] idle_i);
|
||||
integer count;
|
||||
count = 0;
|
||||
for (
|
||||
integer target_index = 0; target_index < `RETROSOC_TINY__TARGET_COUNT; target_index++
|
||||
) begin
|
||||
if (idle_i[target_index] === 1'b0) count++;
|
||||
else if (idle_i[target_index] !== 1'b1) $fatal(1, "SIM_TEST_FAIL P5 unknown target state");
|
||||
end
|
||||
return count;
|
||||
endfunction
|
||||
initial begin : p5_monitor_check
|
||||
if ($test$plusargs("tiny_r2_p5_monitor_check")) begin
|
||||
for (integer active = 0; active <= `RETROSOC_TINY__TARGET_COUNT; active++) begin
|
||||
if (p5_active_targets(
|
||||
{`RETROSOC_TINY__TARGET_COUNT{1'b1}} ^ ((`RETROSOC_TINY__TARGET_COUNT'(1) << active) - `RETROSOC_TINY__TARGET_COUNT'(1))
|
||||
) != active)
|
||||
$fatal(1, "SIM_TEST_FAIL P5 monitor population count");
|
||||
end
|
||||
$display("SIM_TEST_PASS Tiny P5 monitor-check counts=0..27; instrumentation only");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
always @(posedge s_clk) begin
|
||||
s_ahb_cycle = s_ahb_cycle + 1;
|
||||
if (!u_dut.u_soc.s_rst_n) begin
|
||||
s_ahb_pending = 1'b0;
|
||||
s_ahb_measured = 1'b0;
|
||||
s_ahb_previous_enable = 1'b0;
|
||||
s_ahb_window = 0;
|
||||
s_p5_previous_enable = 0;
|
||||
s_p5_window = 0;
|
||||
end else if ($test$plusargs("tiny_r2_p5")) begin
|
||||
if (s_p5_enable && !s_p5_previous_enable) begin
|
||||
s_p5_window++;
|
||||
s_p5_overlap = 0;
|
||||
s_p5_beat_overlap = 0;
|
||||
s_p5_active_max = 0;
|
||||
end
|
||||
if (s_p5_enable) begin
|
||||
if (p5_active_targets(u_dut.u_soc.u_fabric.target_idle_o) > s_p5_active_max)
|
||||
s_p5_active_max = p5_active_targets(u_dut.u_soc.u_fabric.target_idle_o);
|
||||
if (u_dut.u_soc.u_fabric.s_busy_q[2] && u_dut.u_soc.u_fabric.s_busy_q[3]) s_p5_overlap++;
|
||||
if (u_dut.u_soc.u_masters_axi4_if[1].rvalid && u_dut.u_soc.u_masters_axi4_if[1].rready &&
|
||||
u_dut.u_soc.u_masters_axi4_if[1].wvalid && u_dut.u_soc.u_masters_axi4_if[1].wready)
|
||||
s_p5_beat_overlap++;
|
||||
end
|
||||
if (!s_p5_enable && s_p5_previous_enable)
|
||||
$display(
|
||||
"R2_P5_FABRIC window=%0d active_targets_max=%0d dma_rw_overlap_cycles=%0d dma_rw_beat_overlap_cycles=%0d",
|
||||
s_p5_window,
|
||||
s_p5_active_max,
|
||||
s_p5_overlap,
|
||||
s_p5_beat_overlap
|
||||
);
|
||||
s_p5_previous_enable = s_p5_enable;
|
||||
end
|
||||
end
|
||||
|
||||
// Verification-only per-group issue/conflict accounting. A bank conflict is
|
||||
// two or more eligible macro clients in one cycle, not an AXI address stall.
|
||||
for (genvar group = 0; group < 4; group++) begin : gen_bank_observer
|
||||
longint unsigned s_issues[3], s_waits[3];
|
||||
longint unsigned s_conflicts = 0;
|
||||
logic s_previous_enable = 0;
|
||||
integer s_window = 0;
|
||||
wire s_enable = u_dut.u_soc.s_perf_enable && s_baseline_enabled;
|
||||
wire [2:0] s_req = u_dut.u_soc.u_sram.gen_group[group].u_group.s_req;
|
||||
wire [2:0] s_grant = u_dut.u_soc.u_sram.gen_group[group].u_group.s_grant;
|
||||
always @(posedge s_clk) begin
|
||||
if (!u_dut.u_soc.s_rst_n) begin
|
||||
s_previous_enable = 0;
|
||||
s_window = 0;
|
||||
end else if (s_baseline_enabled) begin
|
||||
if (s_ahb_enable && !s_ahb_previous_enable) begin
|
||||
s_ahb_window = s_ahb_window + 1;
|
||||
s_ahb_measured = 1'b0;
|
||||
for (int kind = 0; kind < 2; kind++) begin
|
||||
s_ahb_accept[kind] = 0;
|
||||
s_ahb_done[kind] = 0;
|
||||
s_ahb_latency[kind] = 0;
|
||||
if (s_enable && !s_previous_enable) begin
|
||||
s_window = s_window + 1;
|
||||
s_conflicts = 0;
|
||||
for (int client = 0; client < 3; client++) begin
|
||||
s_issues[client] = 0;
|
||||
s_waits[client] = 0;
|
||||
end
|
||||
end
|
||||
if (`_BASELINE_AHB.hready) begin
|
||||
if (s_ahb_pending && s_ahb_measured && s_ahb_enable) begin
|
||||
s_ahb_done[s_ahb_data] = s_ahb_done[s_ahb_data] + 1;
|
||||
if ((s_ahb_cycle - s_ahb_start) > s_ahb_latency[s_ahb_data])
|
||||
s_ahb_latency[s_ahb_data] = s_ahb_cycle - s_ahb_start;
|
||||
end
|
||||
s_ahb_pending = `_BASELINE_AHB.htrans[1];
|
||||
s_ahb_measured = s_ahb_pending && s_ahb_enable;
|
||||
if (s_ahb_measured) begin
|
||||
s_ahb_data = `_BASELINE_AHB.hprot[0];
|
||||
s_ahb_start = s_ahb_cycle;
|
||||
s_ahb_accept[s_ahb_data] = s_ahb_accept[s_ahb_data] + 1;
|
||||
if (s_enable) begin
|
||||
if ((s_req & (s_req - 3'd1)) != 3'd0) s_conflicts = s_conflicts + 1;
|
||||
for (int client = 0; client < 3; client++) begin
|
||||
if (s_grant[client]) s_issues[client] = s_issues[client] + 1;
|
||||
if (s_req[client] && !s_grant[client]) s_waits[client] = s_waits[client] + 1;
|
||||
end
|
||||
end
|
||||
if (!s_ahb_enable && s_ahb_previous_enable) begin
|
||||
for (int kind = 0; kind < 2; kind++) begin
|
||||
if (!s_enable && s_previous_enable)
|
||||
$display(
|
||||
"R2_P4_BANK window=%0d group=%0d issues_i=%0d issues_d=%0d issues_external=%0d conflicts=%0d wait_i=%0d wait_d=%0d wait_external=%0d",
|
||||
s_window,
|
||||
group,
|
||||
s_issues[0],
|
||||
s_issues[1],
|
||||
s_issues[2],
|
||||
s_conflicts,
|
||||
s_waits[0],
|
||||
s_waits[1],
|
||||
s_waits[2]
|
||||
);
|
||||
s_previous_enable = s_enable;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// P4 retains the original per-kind record format, now observed on two
|
||||
// independent ports. External AXI counts remain external traffic only.
|
||||
for (genvar port_index = 0; port_index < 2; port_index++) begin : gen_ahb_observer
|
||||
longint unsigned s_cycle = 0, s_start = 0;
|
||||
longint unsigned s_accepted = 0, s_completed = 0, s_latency = 0;
|
||||
longint unsigned s_local_accepted = 0, s_local_completed = 0, s_local_latency = 0;
|
||||
longint unsigned s_admission_wait = 0;
|
||||
logic s_pending = 0, s_measured = 0, s_local = 0, s_previous_enable = 0;
|
||||
integer s_window = 0;
|
||||
wire s_enable = u_dut.u_soc.s_perf_enable && s_baseline_enabled;
|
||||
`define _P4_AHB u_dut.u_soc.u_cpu_ahbl_if[port_index]
|
||||
always @(posedge s_clk) begin
|
||||
s_cycle = s_cycle + 1;
|
||||
if (!u_dut.u_soc.s_core_rst_n) begin
|
||||
s_pending = 0;
|
||||
s_measured = 0;
|
||||
s_previous_enable = 0;
|
||||
s_window = 0;
|
||||
end else if (s_baseline_enabled) begin
|
||||
if (s_enable && !s_previous_enable) begin
|
||||
s_window = s_window + 1;
|
||||
s_measured = 0;
|
||||
s_accepted = 0;
|
||||
s_completed = 0;
|
||||
s_latency = 0;
|
||||
s_local_accepted = 0;
|
||||
s_local_completed = 0;
|
||||
s_local_latency = 0;
|
||||
s_admission_wait = 0;
|
||||
end
|
||||
if (s_enable && `_P4_AHB.htrans[1] && !`_P4_AHB.hready)
|
||||
s_admission_wait = s_admission_wait + 1;
|
||||
if (`_P4_AHB.hready) begin
|
||||
if (s_pending && s_measured && s_enable) begin
|
||||
s_completed = s_completed + 1;
|
||||
if ((s_cycle - s_start) > s_latency) s_latency = s_cycle - s_start;
|
||||
if (s_local) begin
|
||||
s_local_completed = s_local_completed + 1;
|
||||
if ((s_cycle - s_start) > s_local_latency) s_local_latency = s_cycle - s_start;
|
||||
end
|
||||
end
|
||||
s_pending = `_P4_AHB.htrans[1];
|
||||
s_measured = s_pending && s_enable;
|
||||
if (s_measured) begin
|
||||
s_start = s_cycle;
|
||||
s_accepted = s_accepted + 1;
|
||||
s_local = (`_P4_AHB.haddr >= 32'h30000000) && (`_P4_AHB.haddr < 32'h30020000);
|
||||
if (s_local) s_local_accepted = s_local_accepted + 1;
|
||||
end
|
||||
end
|
||||
if (!s_enable && s_previous_enable) begin
|
||||
$display("R2_AHB window=%0d kind=%0d accepted=%0d completed=%0d latency_max=%0d",
|
||||
s_ahb_window, kind, s_ahb_accept[kind], s_ahb_done[kind], s_ahb_latency[kind]);
|
||||
s_window, port_index, s_accepted, s_completed, s_latency);
|
||||
$display(
|
||||
"R2_P4_LOCAL window=%0d port=%0d accepted=%0d completed=%0d latency_max=%0d admission_wait=%0d",
|
||||
s_window, port_index, s_local_accepted, s_local_completed, s_local_latency,
|
||||
s_admission_wait);
|
||||
end
|
||||
s_previous_enable = s_enable;
|
||||
end
|
||||
end
|
||||
s_ahb_previous_enable = s_ahb_enable;
|
||||
`undef _P4_AHB
|
||||
end
|
||||
end
|
||||
`undef _BASELINE_AHB
|
||||
`endif
|
||||
|
||||
retrosoc_tiny_asic u_dut (
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
// Verification-only external devices on the Gen1 GPIO routes. No DUT state is driven.
|
||||
logic s_p6_io_trace_started = 0;
|
||||
always @(negedge u_dut.u_soc.s_i2c0_clk) begin
|
||||
if ($test$plusargs("p6_debug_io")) begin
|
||||
if (u_dut.u_soc.u_i2c0.s_cmd_valid && !s_p6_io_trace_started) begin
|
||||
s_p6_io_trace_started = 1;
|
||||
$display("P6_IO_DIAGNOSTIC start pads=%b raw=%b%b filtered=%b%b drive=%b%b", s_gpio[11:10],
|
||||
u_dut.u_soc.u_i2c0_if.sda_i, u_dut.u_soc.u_i2c0_if.scl_i,
|
||||
u_dut.u_soc.u_i2c0.s_sda_filtered, u_dut.u_soc.u_i2c0.s_scl_filtered,
|
||||
u_dut.u_soc.u_i2c0.s_sda_pull_low, u_dut.u_soc.u_i2c0.s_scl_pull_low);
|
||||
$fflush();
|
||||
end
|
||||
if (u_dut.u_soc.u_i2c0.s_addr_nack_event || u_dut.u_soc.u_i2c0.s_bus_timeout_event ||
|
||||
u_dut.u_soc.u_i2c0.s_cmd_timeout_event || u_dut.u_soc.u_i2c0.s_stretch_timeout_event ||
|
||||
u_dut.u_soc.u_i2c0.s_arb_lost_event) begin
|
||||
$display(
|
||||
"P6_IO_DIAGNOSTIC nack=%b bus_timeout=%b command_timeout=%b stretch=%b arbitration=%b pads=%b drive=%b%b",
|
||||
u_dut.u_soc.u_i2c0.s_addr_nack_event, u_dut.u_soc.u_i2c0.s_bus_timeout_event,
|
||||
u_dut.u_soc.u_i2c0.s_cmd_timeout_event, u_dut.u_soc.u_i2c0.s_stretch_timeout_event,
|
||||
u_dut.u_soc.u_i2c0.s_arb_lost_event, s_gpio[11:10], u_dut.u_soc.u_i2c0.s_sda_pull_low,
|
||||
u_dut.u_soc.u_i2c0.s_scl_pull_low);
|
||||
$finish; // Diagnostic only: deliberately no SIM_TEST_PASS verdict.
|
||||
end
|
||||
end
|
||||
end
|
||||
`define _P6_WS u_dut.u_soc.u_ws2812
|
||||
logic s_p6_uart_rx = 1;
|
||||
logic [7:0] s_p6_uart_byte;
|
||||
logic [7:0] s_p6_uart_packet [4];
|
||||
integer s_p6_uart_index = 0, s_p6_uart_routes = 0;
|
||||
assign s_gpio_9 = s_p6_uart_rx;
|
||||
initial begin
|
||||
forever begin
|
||||
@(negedge s_gpio_8);
|
||||
#1627.604;
|
||||
for (integer bit_index = 0; bit_index < 8; bit_index++) begin
|
||||
s_p6_uart_byte[bit_index] = s_gpio_8;
|
||||
#1085.069;
|
||||
end
|
||||
if (s_p6_uart_index != 0 || s_p6_uart_byte == 8'ha5) begin
|
||||
s_p6_uart_packet[s_p6_uart_index] = s_p6_uart_byte;
|
||||
s_p6_uart_index++;
|
||||
if (s_p6_uart_index == 4) begin
|
||||
if (s_p6_uart_packet[0] != 8'ha5 || s_p6_uart_packet[1] != 8'h5a ||
|
||||
s_p6_uart_packet[2] != 8'h96 || s_p6_uart_packet[3] != 8'h69)
|
||||
$fatal(1, "SIM_TEST_FAIL P6 UART GPIO8 framing/data");
|
||||
for (integer byte_index = 0; byte_index < 4; byte_index++) begin
|
||||
s_p6_uart_rx = 0;
|
||||
#1085.069;
|
||||
for (integer bit_index = 0; bit_index < 8; bit_index++) begin
|
||||
s_p6_uart_rx = s_p6_uart_packet[byte_index][bit_index];
|
||||
#1085.069;
|
||||
end
|
||||
s_p6_uart_rx = 1;
|
||||
#1085.069;
|
||||
end
|
||||
s_p6_uart_index = 0;
|
||||
s_p6_uart_routes++;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
integer s_p6_frames = 0, s_p6_completed = 0, s_p6_underflows = 0, s_p6_aborts = 0;
|
||||
longint unsigned s_p6_sdio_overlap = 0, s_p6_overlap_fetches = 0;
|
||||
always @(posedge u_dut.u_soc.s_exec_clk) begin
|
||||
if (u_dut.u_soc.u_dma.s_busy[2] && u_dut.u_soc.u_sdio.s_dma_status[0]) begin
|
||||
s_p6_sdio_overlap++;
|
||||
if (u_dut.u_soc.u_cpu_ahbl_if[0].hready && u_dut.u_soc.u_cpu_ahbl_if[0].htrans[1])
|
||||
s_p6_overlap_fetches++;
|
||||
end
|
||||
end
|
||||
integer s_p6_word = 0, s_p6_bit = 0, s_p6_bit_cycle = 0, s_p6_reset_cycles = 0;
|
||||
integer s_p6_ws_wait = 0, s_p6_ws_wait_max = 0, s_p6_fifo_max = 0;
|
||||
integer s_p6_clock_stops = 0;
|
||||
integer s_p6_wire_cases = 0, s_p6_wire_matched = 0, s_p6_wire_examined = 0;
|
||||
integer s_p6_wire_edges = 0;
|
||||
logic s_p6_wire_found = 0, s_p6_wire_boundary = 0, s_p6_wire_lrck = 0;
|
||||
logic [23:0] s_p6_wire_shift = 0;
|
||||
logic [31:0] s_p6_wire_word;
|
||||
wire s_p6_audio_enabled = u_dut.u_soc.u_i2s.u_i2s_core.enable_i;
|
||||
wire s_p6_audio_wide = u_dut.u_soc.u_i2s.u_i2s_core.s_bitmode;
|
||||
// Decode actual BCLK/LRCLK/DOUT pads, independently of the receive engine.
|
||||
always @(posedge s_gpio[12] or negedge s_p6_audio_enabled) begin
|
||||
if (!s_p6_audio_enabled) begin
|
||||
if (s_p6_wire_found) begin
|
||||
if (s_p6_wire_matched != 512) $fatal(1, "SIM_TEST_FAIL P6 truncated I2S wire payload");
|
||||
s_p6_wire_cases++;
|
||||
$display("R2_P6_I2S_WIRE bits=%0d samples=%0d", s_p6_audio_wide ? 24 : 16, s_p6_wire_matched);
|
||||
end
|
||||
s_p6_wire_matched = 0;
|
||||
s_p6_wire_examined = 0;
|
||||
s_p6_wire_edges = 0;
|
||||
s_p6_wire_found = 0;
|
||||
s_p6_wire_boundary = 0;
|
||||
s_p6_wire_lrck = 0;
|
||||
s_p6_wire_shift = 0;
|
||||
end else begin
|
||||
if (s_gpio[14] !== 1'b0 && s_gpio[14] !== 1'b1) $fatal(1, "SIM_TEST_FAIL P6 unknown I2S DOUT");
|
||||
s_p6_wire_shift = {s_p6_wire_shift[22:0], s_gpio[14]};
|
||||
s_p6_wire_edges++;
|
||||
if (s_gpio[13] != s_p6_wire_lrck) begin
|
||||
if (s_p6_wire_boundary && s_p6_wire_edges != (s_p6_audio_wide ? 24 : 16))
|
||||
$fatal(1, "SIM_TEST_FAIL P6 I2S slot length");
|
||||
s_p6_wire_boundary = 1;
|
||||
s_p6_wire_edges = 0;
|
||||
s_p6_wire_word = s_p6_audio_wide ? {8'd0, s_p6_wire_shift} : {16'd0, s_p6_wire_shift[15:0]};
|
||||
if (!s_p6_wire_found && s_p6_wire_word == (s_p6_audio_wide ? 32'h120020 : 32'h2020))
|
||||
s_p6_wire_found = 1;
|
||||
if (s_p6_wire_found && s_p6_wire_matched < 512) begin
|
||||
if (s_p6_wire_word != (s_p6_audio_wide ? 32'h120020 : 32'h2020) + 32'(s_p6_wire_matched))
|
||||
$fatal(1, "SIM_TEST_FAIL P6 I2S wire ordering/data index=%0d", s_p6_wire_matched);
|
||||
s_p6_wire_matched++;
|
||||
end
|
||||
s_p6_wire_examined++;
|
||||
if (!s_p6_wire_found && s_p6_wire_examined > 40)
|
||||
$fatal(1, "SIM_TEST_FAIL P6 missing I2S wire payload");
|
||||
s_p6_wire_lrck = s_gpio[13];
|
||||
end
|
||||
end
|
||||
end
|
||||
logic s_p6_busy_previous = 0;
|
||||
logic [23:0] s_p6_pixel;
|
||||
logic s_p6_expected_high;
|
||||
logic s_p6_audio_reference = 1'b0;
|
||||
logic s_p6_audio_running = 1'b0;
|
||||
initial begin
|
||||
repeat (200) @(negedge u_dut.u_soc.s_ref_clk);
|
||||
if (!u_dut.u_soc.s_cpu_ready_rst_n)
|
||||
$fatal(1, "SIM_TEST_FAIL CPU boot waited for absent AUDIO clock");
|
||||
s_p6_audio_running = 1'b1;
|
||||
end
|
||||
// GPIO27 is a verification-board control only after the four normal WS frames.
|
||||
// Stop low and high in separate cases, then restore the source without DUT forcing.
|
||||
always @(posedge s_gpio[27]) begin
|
||||
if (s_p6_frames == 4 && s_p6_clock_stops < 2) begin
|
||||
wait (s_p6_audio_reference == (s_p6_clock_stops != 0));
|
||||
s_p6_audio_running = 0;
|
||||
repeat (4800) @(negedge u_dut.u_soc.s_ref_clk);
|
||||
s_p6_clock_stops++;
|
||||
s_p6_audio_running = 1;
|
||||
end
|
||||
end
|
||||
always @(negedge u_dut.u_soc.s_ws2812_clk) begin
|
||||
if (`_P6_WS.s_busy && !s_p6_busy_previous) begin
|
||||
s_p6_frames++;
|
||||
s_p6_word = 0;
|
||||
s_p6_bit = 0;
|
||||
s_p6_bit_cycle = 0;
|
||||
s_p6_reset_cycles = 0;
|
||||
end
|
||||
if (`_P6_WS.s_underflow) s_p6_underflows++;
|
||||
if (`_P6_WS.s_aborted) s_p6_aborts++;
|
||||
if (`_P6_WS.s_busy && !`_P6_WS.s_reset_active && s_p6_frames <= 4) begin
|
||||
s_p6_pixel = 24'(s_p6_word * 32'h010203);
|
||||
s_p6_expected_high = s_p6_bit_cycle < (s_p6_pixel[23-s_p6_bit] ? 17 : 8);
|
||||
if (s_gpio[26] !== s_p6_expected_high)
|
||||
$fatal(
|
||||
1,
|
||||
"SIM_TEST_FAIL Tiny P6 WS pad waveform frame=%0d word=%0d bit=%0d cycle=%0d",
|
||||
s_p6_frames,
|
||||
s_p6_word,
|
||||
s_p6_bit,
|
||||
s_p6_bit_cycle
|
||||
);
|
||||
s_p6_bit_cycle++;
|
||||
if (s_p6_bit_cycle == 30) begin
|
||||
s_p6_bit_cycle = 0;
|
||||
s_p6_bit++;
|
||||
if (s_p6_bit == 24) begin
|
||||
s_p6_bit = 0;
|
||||
s_p6_word++;
|
||||
end
|
||||
end
|
||||
if (`_P6_WS.u_ws2812_reg.s_fifo_level > s_p6_fifo_max)
|
||||
s_p6_fifo_max = integer'(`_P6_WS.u_ws2812_reg.s_fifo_level);
|
||||
if (`_P6_WS.u_ws2812_reg.s_fifo_low && !`_P6_WS.u_ws2812_reg.s_tx_push) s_p6_ws_wait++;
|
||||
else s_p6_ws_wait = 0;
|
||||
if (s_p6_ws_wait > s_p6_ws_wait_max) s_p6_ws_wait_max = s_p6_ws_wait;
|
||||
if (s_p6_ws_wait > 4800 || s_p6_fifo_max > 16)
|
||||
$fatal(1, "SIM_TEST_FAIL Tiny P6 WS service budget/occupancy");
|
||||
end else s_p6_ws_wait = 0;
|
||||
if (`_P6_WS.s_reset_active) begin
|
||||
if (s_gpio[26] !== 1'b0) $fatal(1, "SIM_TEST_FAIL Tiny P6 WS reset-low");
|
||||
s_p6_reset_cycles++;
|
||||
end
|
||||
if (!`_P6_WS.s_busy && s_p6_busy_previous) begin
|
||||
if (s_p6_reset_cycles < 7200) $fatal(1, "SIM_TEST_FAIL Tiny P6 WS reset interval");
|
||||
if (s_p6_frames <= 4) begin
|
||||
if (s_p6_word != ((s_p6_frames % 2) ? 33 : 65) || s_p6_bit != 0 || s_p6_bit_cycle != 0)
|
||||
$fatal(1, "SIM_TEST_FAIL Tiny P6 WS exact frame length");
|
||||
s_p6_completed++;
|
||||
end
|
||||
end
|
||||
s_p6_busy_previous = `_P6_WS.s_busy;
|
||||
end
|
||||
final begin
|
||||
if (u_dut.s_test_done && u_dut.s_test_pass && s_p6_frames != 0) begin
|
||||
if (s_p6_sdio_overlap == 0 || s_p6_overlap_fetches == 0)
|
||||
$fatal(1, "SIM_TEST_FAIL P6 missing actual SDIO/DMA/CPU contention");
|
||||
$display("R2_P6_CONTENTION sdio_dma_cycles=%0d cpu_fetches=%0d", s_p6_sdio_overlap,
|
||||
s_p6_overlap_fetches);
|
||||
if (s_p6_completed != 4 || s_p6_underflows != 1 || s_p6_aborts != 1 ||
|
||||
s_p6_clock_stops != 2 || s_p6_wire_cases != 2 || s_p6_uart_routes != 1)
|
||||
$fatal(1, "SIM_TEST_FAIL Tiny P6 incomplete device coverage");
|
||||
$display(
|
||||
"R2_P6_DEVICES ws_frames=%0d ws_wait_max=%0d fifo_max=%0d underflows=%0d aborts=%0d clock_stops=%0d",
|
||||
s_p6_completed, s_p6_ws_wait_max, s_p6_fifo_max, s_p6_underflows, s_p6_aborts,
|
||||
s_p6_clock_stops);
|
||||
end
|
||||
end
|
||||
`undef _P6_WS
|
||||
// Counts describe observed bus handshakes over the complete acceptance run.
|
||||
// Read bytes require OKAY; write bytes are accepted W strobes, not rollback claims.
|
||||
for (genvar owner = 0; owner < 3; owner++) begin : gen_p6_axi_observer
|
||||
longint unsigned read_bytes = 0, write_bytes = 0, descriptor_bytes = 0;
|
||||
longint unsigned ar_wait = 0, aw_wait = 0, w_wait = 0, r_wait = 0, b_wait = 0;
|
||||
longint unsigned ar_max = 0, aw_max = 0, w_max = 0, r_max = 0, b_max = 0;
|
||||
logic pending_read = 0, pending_write = 0, descriptor = 0;
|
||||
logic [2:0] read_size = 0;
|
||||
`define _P6_AXI u_dut.u_soc.u_masters_axi4_if[owner]
|
||||
always @(posedge u_dut.u_soc.s_exec_clk) begin
|
||||
if (!u_dut.u_soc.s_fabric_rst_n) begin
|
||||
pending_read = 0;
|
||||
pending_write = 0;
|
||||
end else begin
|
||||
if (`_P6_AXI.arvalid && `_P6_AXI.arready) begin
|
||||
if (pending_read) $fatal(1, "SIM_TEST_FAIL P6 duplicate read admission");
|
||||
pending_read = 1;
|
||||
read_size = `_P6_AXI.arsize;
|
||||
descriptor = owner == 1 && u_dut.u_soc.u_dma.s_tcd_count[64+:32] != 0 &&
|
||||
`_P6_AXI.araddr >= u_dut.u_soc.u_dma.s_tcd_head[64+:32] &&
|
||||
`_P6_AXI.araddr < u_dut.u_soc.u_dma.s_tcd_head[64+:32] + 32'd256;
|
||||
end
|
||||
if (`_P6_AXI.rvalid && `_P6_AXI.rready) begin
|
||||
if (!pending_read) $fatal(1, "SIM_TEST_FAIL P6 unsolicited read response");
|
||||
if (`_P6_AXI.rresp == 0) begin
|
||||
read_bytes += 64'd1 << read_size;
|
||||
if (descriptor) descriptor_bytes += 64'd1 << read_size;
|
||||
end
|
||||
if (`_P6_AXI.rlast) pending_read = 0;
|
||||
end
|
||||
if (`_P6_AXI.awvalid && `_P6_AXI.awready) begin
|
||||
if (pending_write) $fatal(1, "SIM_TEST_FAIL P6 duplicate write admission");
|
||||
pending_write = 1;
|
||||
end
|
||||
if (`_P6_AXI.wvalid && `_P6_AXI.wready) begin
|
||||
if (!pending_write) $fatal(1, "SIM_TEST_FAIL P6 W without saved AW");
|
||||
for (integer lane = 0; lane < 4; lane++) if (`_P6_AXI.wstrb[lane]) write_bytes++;
|
||||
end
|
||||
if (`_P6_AXI.bvalid && `_P6_AXI.bready) begin
|
||||
if (!pending_write) $fatal(1, "SIM_TEST_FAIL P6 unsolicited write response");
|
||||
pending_write = 0;
|
||||
end
|
||||
ar_wait = `_P6_AXI.arvalid && !`_P6_AXI.arready ? ar_wait + 1 : 0;
|
||||
aw_wait = `_P6_AXI.awvalid && !`_P6_AXI.awready ? aw_wait + 1 : 0;
|
||||
w_wait = `_P6_AXI.wvalid && !`_P6_AXI.wready ? w_wait + 1 : 0;
|
||||
r_wait = `_P6_AXI.rvalid && !`_P6_AXI.rready ? r_wait + 1 : 0;
|
||||
b_wait = `_P6_AXI.bvalid && !`_P6_AXI.bready ? b_wait + 1 : 0;
|
||||
if (ar_wait > ar_max) ar_max = ar_wait;
|
||||
if (aw_wait > aw_max) aw_max = aw_wait;
|
||||
if (w_wait > w_max) w_max = w_wait;
|
||||
if (r_wait > r_max) r_max = r_wait;
|
||||
if (b_wait > b_max) b_max = b_wait;
|
||||
end
|
||||
end
|
||||
final begin
|
||||
if (u_dut.s_test_done && u_dut.s_test_pass && s_p6_frames != 0) begin
|
||||
if (pending_read || pending_write) $fatal(1, "SIM_TEST_FAIL P6 unretired accepted work");
|
||||
$display(
|
||||
"R2_P6_AXI owner=%0d read_bytes=%0d write_bytes=%0d descriptor_bytes=%0d ar_stall_max=%0d aw_stall_max=%0d w_stall_max=%0d r_stall_max=%0d b_stall_max=%0d",
|
||||
owner, read_bytes, write_bytes, descriptor_bytes, ar_max, aw_max, w_max, r_max, b_max);
|
||||
end
|
||||
end
|
||||
`undef _P6_AXI
|
||||
end
|
||||
always #27.126736111 if (s_p6_audio_running) s_p6_audio_reference = !s_p6_audio_reference;
|
||||
assign s_gpio_17 = s_p6_audio_reference;
|
||||
// The first integration case is an external codec loopback, across actual pads.
|
||||
// Independent wire decoding and error injection supplement firmware readback.
|
||||
assign s_gpio_15 = s_gpio_14;
|
||||
wire s_p6_card_cmd;
|
||||
wire [3:0] s_p6_card_data;
|
||||
wire s_p6_card_irq;
|
||||
sdio_native_card_model #(
|
||||
.MemoryInitialization(1'b1),
|
||||
.BlockCount (1024)
|
||||
) u_p6_card (
|
||||
.rst_n_i (s_rst_n),
|
||||
.sck_i (s_gpio[0]),
|
||||
.cmd_oe_i(u_dut.u_soc.u_sdio_if.cmd_oe_o),
|
||||
.cmd_do_i(s_gpio[1]),
|
||||
.cmd_do_o(s_p6_card_cmd),
|
||||
.dat_oe_i(u_dut.u_soc.u_sdio_if.dat_oe_o),
|
||||
.dat_do_i(s_gpio[5:2]),
|
||||
.dat_do_o(s_p6_card_data),
|
||||
.irq_o (s_p6_card_irq)
|
||||
);
|
||||
assign s_gpio_1 = u_dut.u_soc.u_sdio_if.cmd_oe_o ? 1'bz : s_p6_card_cmd;
|
||||
assign s_gpio_2 = u_dut.u_soc.u_sdio_if.dat_oe_o[0] ? 1'bz : s_p6_card_data[0];
|
||||
assign s_gpio_3 = u_dut.u_soc.u_sdio_if.dat_oe_o[1] ? 1'bz : s_p6_card_data[1];
|
||||
assign s_gpio_4 = u_dut.u_soc.u_sdio_if.dat_oe_o[2] ? 1'bz : s_p6_card_data[2];
|
||||
assign s_gpio_5 = u_dut.u_soc.u_sdio_if.dat_oe_o[3] ? 1'bz : s_p6_card_data[3];
|
||||
always @(negedge u_dut.u_soc.s_sdio_clk) begin
|
||||
// Reuse the standalone card's explicit data-stimulus API. The wire command
|
||||
// fixes direction/address/length; host DATA_START only schedules admission.
|
||||
// This is repository controller integration evidence, not card compliance.
|
||||
if (u_dut.u_soc.u_sdio.s_data_start) begin
|
||||
if (u_p6_card.s_last_cmd != 17 && u_p6_card.s_last_cmd != 18 && u_p6_card.s_last_cmd != 25)
|
||||
$fatal(1, "SIM_TEST_FAIL P6 unexpected SDIO data command");
|
||||
if (u_dut.u_soc.u_sdio.s_block_size != 512 ||
|
||||
u_dut.u_soc.u_sdio.s_block_count != (u_p6_card.s_last_cmd == 17 ? 1 : 2) ||
|
||||
u_dut.u_soc.u_sdio.s_data_direction != (u_p6_card.s_last_cmd == 25) ||
|
||||
u_dut.u_soc.u_sdio.s_bus_width != (u_p6_card.s_memory_width4 ? 1 : 0))
|
||||
$fatal(1, "SIM_TEST_FAIL P6 SDIO command/data configuration disagreement");
|
||||
u_p6_card.set_data_delay(1);
|
||||
if (u_p6_card.s_last_cmd == 25)
|
||||
u_p6_card.arm_write(integer'(u_p6_card.s_last_arg * 512), 1024, u_p6_card.s_memory_width4,
|
||||
1'b0);
|
||||
else
|
||||
u_p6_card.arm_read(integer'(u_p6_card.s_last_arg * 512),
|
||||
u_p6_card.s_last_cmd == 17 ? 512 : 1024, u_p6_card.s_memory_width4, 1'b0);
|
||||
end
|
||||
if ($test$plusargs("p6_debug_sdio") && u_dut.u_soc.u_sdio.s_cmd_start) begin
|
||||
$display("P6_SDIO_DIAGNOSTIC cmd=%0d argument=%h status=%h", u_dut.u_soc.u_sdio.s_cmd_index,
|
||||
u_dut.u_soc.u_sdio.s_cmd_arg, u_dut.u_soc.u_sdio.s_status);
|
||||
$fflush();
|
||||
end
|
||||
if (u_dut.u_soc.u_sdio.s_cmd_start && u_dut.u_soc.u_sdio.s_cmd_index == 13) begin
|
||||
if (u_dut.u_soc.u_sdio.s_cmd_arg == 32'hbadc0de0) u_p6_card.inject_next_crc_error();
|
||||
if (u_dut.u_soc.u_sdio.s_cmd_arg == 32'hbadc0de1) u_p6_card.inject_next_timeout();
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
// P7-only assertions over production paths. No DUT state is written.
|
||||
logic s_p7_monitor = 0;
|
||||
longint unsigned s_p7_gated_cycles = 0, s_p7_dma_gated_responses = 0;
|
||||
integer s_p7_warm_resets = 0;
|
||||
logic [3:0] s_p7_profiles = 0;
|
||||
initial s_p7_monitor = $test$plusargs("p7_monitor");
|
||||
initial begin
|
||||
if ($test$plusargs("p7_monitor") || $test$plusargs("p7_cold_reset_probe")) begin
|
||||
wait (s_rst_n === 1'b0);
|
||||
@(posedge s_rst_n);
|
||||
wait (u_dut.u_soc.s_cpu_boot_ready === 1'b1);
|
||||
repeat (2) @(negedge u_dut.u_soc.s_ref_clk);
|
||||
// Case comparisons require the exact known reset values in both simulators.
|
||||
if (u_dut.u_soc.u_sysctrl.s_reset_cause_q !== 32'd1 ||
|
||||
u_dut.u_soc.u_sysctrl.s_rcu_fault_q !== 32'd0 ||
|
||||
u_dut.u_soc.s_backend_current !== 2'd0 || u_dut.u_soc.s_gate_request !== 14'd0)
|
||||
$fatal(
|
||||
1,
|
||||
"SIM_TEST_FAIL P7 cold reset state cause=%h fault=%h profile=%h gates=%h",
|
||||
u_dut.u_soc.u_sysctrl.s_reset_cause_q,
|
||||
u_dut.u_soc.u_sysctrl.s_rcu_fault_q,
|
||||
u_dut.u_soc.s_backend_current,
|
||||
u_dut.u_soc.s_gate_request
|
||||
);
|
||||
if ($test$plusargs("p7_cold_reset_probe")) begin
|
||||
$display("P7_COLD_RESET_PASS");
|
||||
$finish; // Diagnostic only; never emits the full Tiny acceptance marker.
|
||||
end
|
||||
end
|
||||
end
|
||||
always @(posedge u_dut.u_soc.s_exec_clk) begin
|
||||
if (s_p7_monitor && u_dut.u_soc.s_actual_gate[0]) begin
|
||||
s_p7_gated_cycles++;
|
||||
if (u_dut.u_soc.u_masters_axi4_if[1].bvalid && u_dut.u_soc.u_masters_axi4_if[1].bready)
|
||||
s_p7_dma_gated_responses++;
|
||||
end
|
||||
end
|
||||
always @(posedge u_dut.u_soc.s_ref_clk) begin
|
||||
if (s_p7_monitor && u_dut.u_soc.s_clock_done) begin
|
||||
s_p7_profiles[u_dut.u_soc.s_backend_current] = 1;
|
||||
$display("P7_CLOCK_COMMIT profile=%0d sys=%0d mem=%0d pclk=%0d", u_dut.u_soc.s_backend_current,
|
||||
u_dut.u_soc.s_backend_sys_hz, u_dut.u_soc.s_backend_mem_hz,
|
||||
u_dut.u_soc.s_backend_pclk_hz);
|
||||
$fflush();
|
||||
end
|
||||
if (s_p7_monitor && u_dut.u_soc.s_system_reset) begin
|
||||
s_p7_warm_resets++;
|
||||
$display("P7_SOFTWARE_RESET request=%0d", s_p7_warm_resets);
|
||||
$fflush();
|
||||
end
|
||||
end
|
||||
final begin
|
||||
if (s_p7_monitor && u_dut.s_test_done && u_dut.s_test_pass) begin
|
||||
if (s_p7_gated_cycles == 0 || s_p7_dma_gated_responses == 0 || s_p7_warm_resets != 1)
|
||||
$fatal(1, "SIM_TEST_FAIL P7 WFI/DMA/software-reset coverage");
|
||||
`ifdef HAVE_PLL
|
||||
if ((s_p7_profiles & 4'b1101) != 4'b1101) $fatal(1, "SIM_TEST_FAIL P7 PLL profile coverage");
|
||||
`else
|
||||
if ((s_p7_profiles & 4'b0011) != 4'b0011)
|
||||
$fatal(1, "SIM_TEST_FAIL P7 external profile coverage");
|
||||
`endif
|
||||
$display("P7_LIFECYCLE_PASS gated_cycles=%0d dma_responses_while_gated=%0d warm_resets=%0d",
|
||||
s_p7_gated_cycles, s_p7_dma_gated_responses, s_p7_warm_resets);
|
||||
end
|
||||
end
|
||||
@@ -22,3 +22,10 @@
|
||||
/clusterip/wdg/rtl/wdg_core.sv
|
||||
/clusterip/wdg/rtl/wdg_reg.sv
|
||||
/clusterip/wdg/rtl/apb4_wdg.sv
|
||||
/clusterip/rng/rtl/rng_core.sv
|
||||
/clusterip/rng/rtl/rng_reg.sv
|
||||
/clusterip/rng/rtl/rng_deterministic_source.sv
|
||||
/clusterip/rng/rtl/apb4_rng.sv
|
||||
/clusterip/crc/rtl/crc_core.sv
|
||||
/clusterip/crc/rtl/crc_reg.sv
|
||||
/clusterip/crc/rtl/apb4_crc.sv
|
||||
@@ -6,6 +6,7 @@
|
||||
/clusterip/common/rtl/interface/axi4_stream_if.sv
|
||||
/clusterip/common/rtl/interface/ram_if.sv
|
||||
/clusterip/common/rtl/utils/register.sv
|
||||
/clusterip/common/rtl/utils/xchecker.sv
|
||||
/clusterip/common/rtl/utils/spill_register.sv
|
||||
/clusterip/common/rtl/stream/round_robin_arbiter.sv
|
||||
/clusterip/common/rtl/utils/lfsr.sv
|
||||
@@ -18,5 +19,7 @@
|
||||
/clusterip/common/rtl/cdc/cdc_2phase.sv
|
||||
/clusterip/common/rtl/clkrst/rst_sync.sv
|
||||
/clusterip/common/rtl/clkrst/counter.sv
|
||||
/clusterip/common/rtl/clock/safe_clock_mux.sv
|
||||
/clusterip/common/rtl/clock/clock_divider.sv
|
||||
/ip/util/soc_common_fifo.sv
|
||||
/ip/util/soc_common_cdc.sv
|
||||
@@ -17,3 +17,6 @@
|
||||
+incdir+/ip/serial
|
||||
+incdir+/ip/peripheral
|
||||
+incdir+/ip/core
|
||||
+incdir+/ip/security
|
||||
+incdir+/clusterip/rng/rtl
|
||||
+incdir+/clusterip/crc/rtl
|
||||
@@ -47,3 +47,40 @@
|
||||
/ip/core/mgmt_debug_wrapper.sv
|
||||
/ip/core/mgmt_core_wrapper.sv
|
||||
/ip/peripheral/gpio_pad_bridge.sv
|
||||
/ip/storage/sdio_if.sv
|
||||
/ip/storage/sdio_pkg.sv
|
||||
/ip/storage/sdio_define.svh
|
||||
/ip/storage/sdio_crc7.sv
|
||||
/ip/storage/sdio_crc16.sv
|
||||
/ip/storage/sdio_clock.sv
|
||||
/ip/storage/sdio_command.sv
|
||||
/ip/storage/sdio_data.sv
|
||||
/ip/storage/sdio_dma_descriptor.sv
|
||||
/ip/serial/i2s_pkg.sv
|
||||
/ip/serial/i2s_reg.sv
|
||||
/ip/serial/i2s_clkgen.sv
|
||||
/ip/serial/i2s_recv.sv
|
||||
/ip/serial/i2s_send.sv
|
||||
/ip/serial/i2s_core.sv
|
||||
/ip/serial/apb4_i2s.sv
|
||||
/ip/serial/ws2812_if.sv
|
||||
/ip/serial/ws2812_reg.sv
|
||||
/ip/serial/ws2812_core.sv
|
||||
/ip/serial/apb4_ws2812.sv
|
||||
/ip/security/crypto_pkg.sv
|
||||
/ip/security/crypto_mem_pkg.sv
|
||||
/ip/security/crypto_define.svh
|
||||
/ip/security/crypto_sram_store.sv
|
||||
/ip/security/crypto_scrubber.sv
|
||||
/ip/security/crypto_clearable_fifo.sv
|
||||
/ip/security/crypto_mem_ctrl.sv
|
||||
/ip/security/crypto_aes_sram_core.sv
|
||||
/ip/security/crypto_aes_sram_engine.sv
|
||||
/ip/security/crypto_sha2_sram_engine.sv
|
||||
/ip/security/crypto_montgomery_sram.sv
|
||||
/ip/security/crypto_rsa_sram_core.sv
|
||||
/ip/security/apb4_crypto.sv
|
||||
/ip/storage/sdio_dma.sv
|
||||
/ip/storage/sdio_reg.sv
|
||||
/ip/storage/sdio_core.sv
|
||||
/ip/storage/apb4_sdio.sv
|
||||
@@ -1,2 +1,3 @@
|
||||
/dv/tiny_qspi_nor.sv
|
||||
/tests/rtl/sdio_native_model.sv
|
||||
/dv/retrosoc_tiny_tb.sv
|
||||
@@ -1,7 +1,24 @@
|
||||
/top/tiny_axi4_target.sv
|
||||
/top/tiny_axi4_fabric.sv
|
||||
/top/tiny_fault_collector.sv
|
||||
/top/tiny_axi42apb4.sv
|
||||
/top/tiny_sysctrl.sv
|
||||
/top/tiny_archinfo.sv
|
||||
/top/tiny_reset_tree.sv
|
||||
/top/tiny_clock_reset_subsystem.sv
|
||||
/top/tiny_axi4_async_bridge.sv
|
||||
/top/tiny_apb_async_bridge.sv
|
||||
/top/tiny_axi4_admission.sv
|
||||
/top/tiny_managed_lifecycle.sv
|
||||
/top/tiny_peripheral_leaf.sv
|
||||
/top/tiny_peripheral_control.sv
|
||||
/top/tiny_clock_output.sv
|
||||
/top/tiny_clock_gate.sv
|
||||
/top/tiny_sram_port_if.sv
|
||||
/top/tiny_sram_group.sv
|
||||
/top/tiny_sram_axi4.sv
|
||||
/top/tiny_sram.sv
|
||||
/top/tiny_cpu_mem.sv
|
||||
/top/tiny_cpu_wrapper.sv
|
||||
/top/retrosoc_tiny.sv
|
||||
/top/retrosoc_tiny_asic.sv
|
||||
@@ -1,31 +1,90 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"inactive_macros": {
|
||||
"ics55_pll": {
|
||||
"cell": "PLL_TOP",
|
||||
"scope": "TINY-ICS55-P1: present, EN=0, no SYS connection",
|
||||
"active_clock_domain": false,
|
||||
"qualification": "no characterized timing arcs; full RCU remains R2-P7"
|
||||
}
|
||||
"external_fabric": {
|
||||
"phase": "TINY-R2-P7",
|
||||
"clock_domain": "system",
|
||||
"target_controllers": "u_soc.u_fabric.gen_target[%d].u_controller",
|
||||
"target_count": 27,
|
||||
"apb_bridges": "SYS frontends; acknowledged per-endpoint crossings to AON, PCLK and MEM",
|
||||
"fabric_reset": "fabric leaf; target reset blocks admission and aborts accepted target work with DECERR",
|
||||
"hart_reset": "CPU-only accepted-work drain; DMA and all target responses stay active",
|
||||
"runtime_peripheral_reset": "RCU blocks admissions, drains accepted work, holds reset for five local edges, waits for local release and bus barriers"
|
||||
},
|
||||
"local_memory": {
|
||||
"phase": "TINY-R2-P4",
|
||||
"clock_domain": "system",
|
||||
"cpu_instance": "u_soc.u_cpu.u_hazard3_cpu_2port",
|
||||
"frontend_instance": "u_soc.u_cpu_mem",
|
||||
"macro_instance": "u_soc.u_sram.gen_group[{group}].u_group.gen_bank[{bank}].u_ram.u_mem",
|
||||
"groups": 4,
|
||||
"macros_per_group": 8,
|
||||
"hart_reset": "halt then drain accepted I/D and slow responses; SRAM/DMA stay active",
|
||||
"main_sram_payload_reset": "none",
|
||||
"local_uncontended_max_cycles": 3
|
||||
},
|
||||
"reset_ports": [
|
||||
"ext_rst_n_i_pad",
|
||||
"jtag_trst_n_i_pad"
|
||||
],
|
||||
"domains": [
|
||||
{
|
||||
"name": "aon",
|
||||
"clock": "s_ref_clk",
|
||||
"reset": "ref_rst_n_o",
|
||||
"reset_source": "rst_n_i",
|
||||
"reset_primitive": "rst_sync",
|
||||
"path": "rtl/tiny/top/tiny_clock_reset_subsystem.sv",
|
||||
"instance": "u_ref_rst",
|
||||
"sta": {
|
||||
"source_port": "extclk_i_pad",
|
||||
"pin": "u_clock_buffer/clk_o",
|
||||
"period_ns": 41.666666667,
|
||||
"async_group": "core"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "system",
|
||||
"clock": "clk_i",
|
||||
"clock": "s_backend_sys_clk",
|
||||
"reset": "system_rst_n_o",
|
||||
"reset_source": "s_system_req_n",
|
||||
"reset_primitive": "rst_sync",
|
||||
"path": "rtl/tiny/top/tiny_reset_tree.sv",
|
||||
"instance": "u_system_rst_sync",
|
||||
"sta": {
|
||||
"source_port": "extclk_i_pad",
|
||||
"pin": "u_clock_buffer/clk_o",
|
||||
"source_domain": "aon",
|
||||
"pin": "u_soc.u_clock_backend.u_sys_mux/clk_o",
|
||||
"period_ns": 41.666666667,
|
||||
"async_group": "system"
|
||||
"async_group": "core"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "memory",
|
||||
"clock": "s_backend_mem_clk",
|
||||
"reset": "s_backend_mem_rst_n",
|
||||
"reset_source": "rst_n_i",
|
||||
"reset_primitive": "rst_sync",
|
||||
"path": "rtl/tiny/top/tiny_clock_reset_subsystem.sv",
|
||||
"instance": "u_mem_rst",
|
||||
"sta": {
|
||||
"source_domain": "system",
|
||||
"pin": "u_soc.u_clock_backend.u_mem_mux/clk_o",
|
||||
"period_ns": 41.666666667,
|
||||
"async_group": "core"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "peripheral",
|
||||
"clock": "s_backend_pclk",
|
||||
"reset": "pclk_rst_n_o",
|
||||
"reset_source": "rst_n_i",
|
||||
"reset_primitive": "rst_sync",
|
||||
"path": "rtl/tiny/top/tiny_clock_reset_subsystem.sv",
|
||||
"instance": "u_pclk_rst",
|
||||
"sta": {
|
||||
"source_domain": "system",
|
||||
"pin": "u_soc.u_clock_backend.u_pclk_mux/clk_o",
|
||||
"period_ns": 41.666666667,
|
||||
"async_group": "core"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -39,31 +98,152 @@
|
||||
"sta": {
|
||||
"source_port": "jtag_tck_i_pad",
|
||||
"object_type": "port",
|
||||
"period_ns": 100.0,
|
||||
"period_ns": 100,
|
||||
"async_group": "jtag"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"clock": "s_audio_clk",
|
||||
"reset": "s_audio_rst_n",
|
||||
"reset_source": "s_i2s_rst_n",
|
||||
"reset_primitive": "rst_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_audio_rst_sync",
|
||||
"sta": {
|
||||
"source_port": "gpio_17_io_pad",
|
||||
"pin": "u_soc.u_audio_clock_buffer/clk_o",
|
||||
"period_ns": 54.253472222,
|
||||
"async_group": "audio"
|
||||
}
|
||||
}
|
||||
],
|
||||
"reset_distribution": {
|
||||
"release_edges": 5,
|
||||
"por": "u_soc.u_reset_tree.u_por_rst_sync",
|
||||
"system": "u_soc.u_reset_tree.u_system_rst_sync",
|
||||
"system_source": "por_rst_n_o && !watchdog_reset_req_i",
|
||||
"system_source": "por_rst_n_o && !watchdog_reset_req_i && backend_reset_n_i",
|
||||
"leaf_instance_pattern": "u_soc.u_reset_tree.gen_leaf[%d].u_leaf_rst_sync",
|
||||
"leaf_names": [
|
||||
"fabric", "gpio", "uart0", "uart1", "timer0", "timer1", "i2c0", "i2c1",
|
||||
"xpi", "dma", "sysctrl", "clint", "sram", "archinfo", "pwm", "rtc", "wdg"
|
||||
"fabric",
|
||||
"gpio",
|
||||
"uart0",
|
||||
"timer0",
|
||||
"timer1",
|
||||
"i2c0",
|
||||
"xpi",
|
||||
"dma",
|
||||
"sysctrl",
|
||||
"clint",
|
||||
"sram",
|
||||
"archinfo",
|
||||
"pwm",
|
||||
"rtc",
|
||||
"wdg",
|
||||
"rng",
|
||||
"crc",
|
||||
"ws2812",
|
||||
"crypto",
|
||||
"i2s",
|
||||
"sdio"
|
||||
],
|
||||
"cpu_prerequisite": "all leaf resets released",
|
||||
"cpu_prerequisite": "all global leaf resets and actual APB/DMA/XPI/RCU barriers; boot readiness latches until the next system reset",
|
||||
"hart": "u_soc.u_cpu.u_mgmt_debug_wrapper.u_mgmt_debug_reset.u_core_rst_sync",
|
||||
"jtag": "u_soc.u_cpu.u_mgmt_debug_wrapper.u_jtag_rst_sync",
|
||||
"dmi": "u_soc.u_cpu.u_mgmt_debug_wrapper.u_dmi_rst_sync",
|
||||
"watchdog_functional_reset": "POR only; APB uses wdg leaf",
|
||||
"watchdog_functional_reset": "REF24 five-edge release after backend retains the watchdog reset event; PCLK APB uses the wdg leaf",
|
||||
"main_sram_payload_reset": "none",
|
||||
"crypto": "not integrated; physical erasure contract unchanged",
|
||||
"clock_domain": "system"
|
||||
"crypto": "six private macro banks; reset invalidates then scrubs/readbacks; CPU does not wait for READY",
|
||||
"clock_domain": "domain-specific",
|
||||
"peripheral": "tiny_peripheral_leaf; five running hold edges and five release edges; I2S additionally requires actual audio-side barrier readiness"
|
||||
},
|
||||
"crossings": [
|
||||
{
|
||||
"name": "debug_pclk_status",
|
||||
"source": "system", "destination": "peripheral", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_debug_pclk_sync"
|
||||
},
|
||||
{
|
||||
"name": "debug_aon_status",
|
||||
"source": "system", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_debug_ref_sync"
|
||||
},
|
||||
{
|
||||
"name": "rtc_wake",
|
||||
"source": "aon", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_rtc_wake_sync"
|
||||
},
|
||||
{
|
||||
"name": "hart_reset_event",
|
||||
"source": "system", "destination": "aon", "primitive": "cdc_2phase",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_hart_event_cdc"
|
||||
},
|
||||
{
|
||||
"name": "peripheral_interrupts",
|
||||
"source": "peripheral", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_irq_sync",
|
||||
"notes": "sticky interrupt levels; this vector also contains AON/MEM and synchronous SYS bits"
|
||||
},
|
||||
{
|
||||
"name": "wfi_permission",
|
||||
"source": "aon", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_wfi_gate_sync"
|
||||
},
|
||||
{
|
||||
"name": "admission_block_system",
|
||||
"source": "aon", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_block_sys"
|
||||
},
|
||||
{
|
||||
"name": "admission_block_dma",
|
||||
"source": "aon", "destination": "peripheral", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_block_pclk"
|
||||
},
|
||||
{
|
||||
"name": "gate_reset_disabled",
|
||||
"source": "aon", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_disabled_sync"
|
||||
},
|
||||
{
|
||||
"name": "peripheral_idle",
|
||||
"source": "peripheral", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_periph_idle_sync"
|
||||
},
|
||||
{
|
||||
"name": "xpi_idle",
|
||||
"source": "memory", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_xpi_idle_sync"
|
||||
},
|
||||
{
|
||||
"name": "dma_ready",
|
||||
"source": "peripheral", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_dma_ready_sync"
|
||||
},
|
||||
{
|
||||
"name": "dma_retirement",
|
||||
"source": "peripheral", "destination": "system", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_dma_idle_sync"
|
||||
},
|
||||
{
|
||||
"name": "fabric_retirement",
|
||||
"source": "system", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_bus_idle_ref"
|
||||
},
|
||||
{
|
||||
"name": "gate_acknowledgements",
|
||||
"source": "peripheral", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_gate_feedback"
|
||||
},
|
||||
{
|
||||
"name": "reset_hold_acknowledgements",
|
||||
"source": "peripheral", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_held_feedback"
|
||||
},
|
||||
{
|
||||
"name": "reset_release_acknowledgements",
|
||||
"source": "system", "destination": "aon", "primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv", "instance": "u_ready_feedback"
|
||||
},
|
||||
{
|
||||
"name": "debug_dmi",
|
||||
"source": "jtag",
|
||||
@@ -72,6 +252,17 @@
|
||||
"path": "rtl/managed/hazard3/hdl/debug/dtm/hazard3_jtag_dtm_core.v",
|
||||
"instance": "inst_hazard3_apb_async_bridge"
|
||||
},
|
||||
{
|
||||
"name": "xpi_mem_axi",
|
||||
"source": "system",
|
||||
"destination": "memory",
|
||||
"primitive": "tiny_axi4_async_bridge",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_xpi_mem_cdc",
|
||||
"source_reset": "s_fabric_rst_n",
|
||||
"destination_reset": "s_xpi_rst_n",
|
||||
"reset_semantics": "five-edge link release; source-owned held responses survive destination reset; drain remaining W before B and synthesize only missing R beats with DECERR; unfinished warm clear requires destination reset before re-admission"
|
||||
},
|
||||
{
|
||||
"name": "debug_hard_reset",
|
||||
"source": "jtag",
|
||||
@@ -79,6 +270,152 @@
|
||||
"primitive": "cdc_sync",
|
||||
"path": "rtl/ip/core/mgmt_debug_wrapper.sv",
|
||||
"instance": "u_dmihardreset_cdc_sync"
|
||||
},
|
||||
{
|
||||
"name": "i2s_configuration",
|
||||
"source": "peripheral",
|
||||
"destination": "audio",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/ip/serial/apb4_i2s.sv",
|
||||
"instance": "u_i2s_cfg_cdc"
|
||||
},
|
||||
{
|
||||
"name": "i2s_commands",
|
||||
"source": "peripheral",
|
||||
"destination": "audio",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/ip/serial/apb4_i2s.sv",
|
||||
"instance": "u_i2s_cmd_cdc"
|
||||
},
|
||||
{
|
||||
"name": "i2s_tx_samples",
|
||||
"source": "peripheral",
|
||||
"destination": "audio",
|
||||
"primitive": "cdc_fifo_warm_flush",
|
||||
"path": "rtl/ip/serial/apb4_i2s.sv",
|
||||
"instance": "u_tx_cdc_fifo"
|
||||
},
|
||||
{
|
||||
"name": "i2s_rx_samples",
|
||||
"source": "audio",
|
||||
"destination": "peripheral",
|
||||
"primitive": "cdc_fifo_warm_flush",
|
||||
"path": "rtl/ip/serial/apb4_i2s.sv",
|
||||
"instance": "u_rx_cdc_fifo"
|
||||
},
|
||||
{
|
||||
"name": "i2s_tx_occupancy",
|
||||
"source": "audio",
|
||||
"destination": "peripheral",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/ip/serial/apb4_i2s.sv",
|
||||
"instance": "u_tx_pop_cnt_cdc"
|
||||
},
|
||||
{
|
||||
"name": "i2s_rx_occupancy",
|
||||
"source": "audio",
|
||||
"destination": "peripheral",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/ip/serial/apb4_i2s.sv",
|
||||
"instance": "u_rx_push_cnt_cdc"
|
||||
},
|
||||
{
|
||||
"name": "dma_axi",
|
||||
"source": "peripheral",
|
||||
"destination": "system",
|
||||
"primitive": "tiny_axi4_async_bridge",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_dma_cdc",
|
||||
"source_reset": "s_dma_rst_n",
|
||||
"destination_reset": "s_fabric_rst_n",
|
||||
"reset_semantics": "five-edge link release; source-owned held responses survive destination reset; drain remaining W before B and synthesize only missing R beats with DECERR; unfinished warm clear requires destination reset before re-admission"
|
||||
},
|
||||
{
|
||||
"name": "rcu_commands",
|
||||
"source": "system",
|
||||
"destination": "aon",
|
||||
"primitive": "tiny_apb_async_bridge",
|
||||
"path": "rtl/tiny/top/tiny_sysctrl.sv",
|
||||
"instance": "u_rcu_cdc"
|
||||
},
|
||||
{
|
||||
"name": "system_rate",
|
||||
"source": "aon",
|
||||
"destination": "system",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_sys_rate_cdc"
|
||||
},
|
||||
{
|
||||
"name": "peripheral_rate",
|
||||
"source": "aon",
|
||||
"destination": "peripheral",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_pclk_rate_cdc"
|
||||
},
|
||||
{
|
||||
"name": "dma_done",
|
||||
"source": "peripheral",
|
||||
"destination": "memory",
|
||||
"primitive": "cdc_2phase",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_dma_done_cdc"
|
||||
},
|
||||
{
|
||||
"name": "xpi_requests",
|
||||
"source": "memory",
|
||||
"destination": "peripheral",
|
||||
"primitive": "cdc_sync",
|
||||
"path": "rtl/tiny/top/retrosoc_tiny.sv",
|
||||
"instance": "u_xpi_stall_sync"
|
||||
}
|
||||
],
|
||||
"clock_contract": "TINY-R2-P7",
|
||||
"macros": {
|
||||
"ics55_pll": {
|
||||
"cell": "PLL_TOP",
|
||||
"scope": "single RCU-owned macro; off after cold reset; selectors 5/7",
|
||||
"active_clock_domain": true,
|
||||
"qualification": "digital activity/rate qualification only; no analog LOCK or characterized timing arcs"
|
||||
}
|
||||
},
|
||||
"generated_apb_crossings": {
|
||||
"generator": "scripts/generate_tiny.py",
|
||||
"template": "tiny_apb_bridges.svh",
|
||||
"primitive": "tiny_apb_async_bridge",
|
||||
"source": "system",
|
||||
"destinations": {
|
||||
"aon": [
|
||||
"clint",
|
||||
"archinfo"
|
||||
],
|
||||
"memory": [
|
||||
"xpi"
|
||||
],
|
||||
"peripheral": [
|
||||
"gpio",
|
||||
"uart0",
|
||||
"timer0",
|
||||
"timer1",
|
||||
"i2c0",
|
||||
"dma",
|
||||
"pwm",
|
||||
"rtc",
|
||||
"wdg",
|
||||
"rng",
|
||||
"crc",
|
||||
"ws2812",
|
||||
"crypto",
|
||||
"i2s"
|
||||
]
|
||||
},
|
||||
"same_clock_isolation": [
|
||||
"sdio"
|
||||
],
|
||||
"native_system": [
|
||||
"sysctrl",
|
||||
"sram"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,50 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"cpu": {
|
||||
"module": "hazard3_cpu_2port",
|
||||
"local_ports": 2,
|
||||
"data_outstanding": 1
|
||||
},
|
||||
"main_sram": {
|
||||
"groups": 4,
|
||||
"group_bytes": 32768,
|
||||
"macros_per_group": 8,
|
||||
"macro_bytes": 4096,
|
||||
"base": "0x30000000",
|
||||
"macro_instance": "u_soc.u_sram.gen_group[{group}].u_group.gen_bank[{bank}].u_ram.u_mem",
|
||||
"external_attachment": "per-target-P5"
|
||||
},
|
||||
"fabric": {
|
||||
"owners": [
|
||||
"cpu_slow",
|
||||
"central_dma",
|
||||
"sdio"
|
||||
],
|
||||
"active_owners": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"cpu_combined_outstanding": 1,
|
||||
"dma_direction_outstanding": 1,
|
||||
"sdio_direction_outstanding": 1,
|
||||
"target_combined_outstanding": 1,
|
||||
"sram_targets": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"xpi_target": 4,
|
||||
"apb_target_base": 5,
|
||||
"decode_error_target": 25,
|
||||
"protocol_error_target": 26,
|
||||
"target_count": 27
|
||||
},
|
||||
"gpio_pins": 32,
|
||||
"irq_vector_width": 32,
|
||||
"external_irq_count": 30,
|
||||
"dma_channels": 4,
|
||||
"dma_channels": 8,
|
||||
"apb_targets": [
|
||||
{
|
||||
"name": "gpio",
|
||||
@@ -18,12 +59,6 @@
|
||||
"APB4_UART0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "uart1",
|
||||
"regions": [
|
||||
"APB4_UART1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "timer0",
|
||||
"regions": [
|
||||
@@ -42,12 +77,6 @@
|
||||
"APB4_I2C0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "i2c1",
|
||||
"regions": [
|
||||
"APB4_I2C1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "xpi",
|
||||
"regions": [
|
||||
@@ -101,6 +130,42 @@
|
||||
"regions": [
|
||||
"APB4_WDG"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rng",
|
||||
"regions": [
|
||||
"APB4_RNG"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "crc",
|
||||
"regions": [
|
||||
"APB4_CRC"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ws2812",
|
||||
"regions": [
|
||||
"APB4_WS2812"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "crypto",
|
||||
"regions": [
|
||||
"APB4_CRYPTO"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "i2s",
|
||||
"regions": [
|
||||
"APB4_I2S"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sdio",
|
||||
"regions": [
|
||||
"APB4_SDIO0"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interrupts": [
|
||||
@@ -134,11 +199,21 @@
|
||||
"core_bit": 7,
|
||||
"signal": "u_i2c0_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "i2s",
|
||||
"core_bit": 8,
|
||||
"signal": "u_i2s_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "xpi",
|
||||
"core_bit": 9,
|
||||
"signal": "s_xpi_irq"
|
||||
},
|
||||
{
|
||||
"name": "sdio",
|
||||
"core_bit": 10,
|
||||
"signal": "u_sdio_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "pwm",
|
||||
"core_bit": 11,
|
||||
@@ -154,36 +229,44 @@
|
||||
"core_bit": 14,
|
||||
"signal": "u_wdg_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "rng",
|
||||
"core_bit": 16,
|
||||
"signal": "s_rng_irq"
|
||||
},
|
||||
{
|
||||
"name": "ws2812",
|
||||
"core_bit": 17,
|
||||
"signal": "u_ws2812_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "gpio",
|
||||
"core_bit": 18,
|
||||
"signal": "u_gpio_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "i2c1",
|
||||
"core_bit": 19,
|
||||
"signal": "u_i2c1_if.irq_o"
|
||||
},
|
||||
{
|
||||
"name": "dma",
|
||||
"core_bit": 20,
|
||||
"signal": "s_dma_irq"
|
||||
},
|
||||
{
|
||||
"name": "uart1",
|
||||
"core_bit": 26,
|
||||
"signal": "u_uart1_if.irq_o"
|
||||
"name": "crypto",
|
||||
"core_bit": 23,
|
||||
"signal": "s_crypto_irq"
|
||||
},
|
||||
{
|
||||
"name": "rcu",
|
||||
"core_bit": 31,
|
||||
"signal": "s_rcu_irq"
|
||||
}
|
||||
],
|
||||
"gpio_alt_functions": [
|
||||
{
|
||||
"pin": 0,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_uart0_if.cts_n_i"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"inputs": [],
|
||||
"do": "u_sdio_if.sck_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
@@ -194,9 +277,11 @@
|
||||
{
|
||||
"pin": 1,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_uart0_if.rts_n_o",
|
||||
"oe": "1'b1"
|
||||
"inputs": [
|
||||
"u_sdio_if.cmd_di_i"
|
||||
],
|
||||
"do": "u_sdio_if.cmd_do_o",
|
||||
"oe": "u_sdio_if.cmd_oe_o"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
@@ -208,10 +293,10 @@
|
||||
"pin": 2,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_pwm_if.sync_i"
|
||||
"u_sdio_if.dat_di_i[0]"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "u_sdio_if.dat_do_o[0]",
|
||||
"oe": "u_sdio_if.dat_oe_o[0]"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
@@ -221,36 +306,243 @@
|
||||
},
|
||||
{
|
||||
"pin": 3,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_sdio_if.dat_di_i[1]"
|
||||
],
|
||||
"do": "u_sdio_if.dat_do_o[1]",
|
||||
"oe": "u_sdio_if.dat_oe_o[1]"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 4,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_sdio_if.dat_di_i[2]"
|
||||
],
|
||||
"do": "u_sdio_if.dat_do_o[2]",
|
||||
"oe": "u_sdio_if.dat_oe_o[2]"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 5,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_sdio_if.dat_di_i[3]"
|
||||
],
|
||||
"do": "u_sdio_if.dat_do_o[3]",
|
||||
"oe": "u_sdio_if.dat_oe_o[3]"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 6,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 7,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 8,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_uart0_if.tx_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[0]",
|
||||
"oe": "u_pwm_if.oe_o[0]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 9,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_uart0_if.rx_i"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[1]",
|
||||
"oe": "u_pwm_if.oe_o[1]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 10,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_i2c0_if.scl_i"
|
||||
],
|
||||
"do": "u_i2c0_if.scl_o",
|
||||
"oe": "u_i2c0_if.scl_oe_o"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[2]",
|
||||
"oe": "u_pwm_if.oe_o[2]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 11,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_i2c0_if.sda_i"
|
||||
],
|
||||
"do": "u_i2c0_if.sda_o",
|
||||
"oe": "u_i2c0_if.sda_oe_o"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[3]",
|
||||
"oe": "u_pwm_if.oe_o[3]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 12,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_i2s_if.sclk_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 13,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_i2s_if.lrck_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 14,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_i2s_if.dacdat_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 15,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_i2s_if.adcdat_i"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 16,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_i2s_if.mclk_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 17,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"s_audio_pad_clk"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 18,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[0]",
|
||||
"oe": "u_pwm_if.oe_o[0]"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [
|
||||
"u_i2c1_if.scl_i"
|
||||
],
|
||||
"do": "u_i2c1_if.scl_o",
|
||||
"oe": "u_i2c1_if.scl_oe_o"
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 4,
|
||||
"pin": 19,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[1]",
|
||||
"oe": "u_pwm_if.oe_o[1]"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [
|
||||
"u_i2c1_if.sda_i"
|
||||
],
|
||||
"do": "u_i2c1_if.sda_o",
|
||||
"oe": "u_i2c1_if.sda_oe_o"
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 5,
|
||||
"pin": 20,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[2]",
|
||||
@@ -263,7 +555,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 6,
|
||||
"pin": 21,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "u_pwm_if.pwm_o[3]",
|
||||
@@ -276,37 +568,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 7,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_i2c0_if.scl_i"
|
||||
],
|
||||
"do": "u_i2c0_if.scl_o",
|
||||
"oe": "u_i2c0_if.scl_oe_o"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 8,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_i2c0_if.sda_i"
|
||||
],
|
||||
"do": "u_i2c0_if.sda_o",
|
||||
"oe": "u_i2c0_if.sda_oe_o"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 9,
|
||||
"pin": 22,
|
||||
"alt0": {
|
||||
"inputs": [
|
||||
"u_pwm_if.fault_i"
|
||||
@@ -320,192 +582,27 @@
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 10,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 11,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 12,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 13,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 14,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 15,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 16,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 17,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 18,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 19,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 20,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 21,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 22,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 23,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"inputs": [
|
||||
"u_pwm_if.sync_i"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "s_clkout",
|
||||
"oe": "s_clkout_enable"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pin": 24,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"inputs": [
|
||||
"u_pwm_if.capture_i[0]"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
@@ -518,7 +615,9 @@
|
||||
{
|
||||
"pin": 25,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"inputs": [
|
||||
"u_pwm_if.capture_i[1]"
|
||||
],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
},
|
||||
@@ -532,8 +631,8 @@
|
||||
"pin": 26,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "u_ws2812_if.dat_o",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
@@ -558,8 +657,8 @@
|
||||
"pin": 28,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "s_clkout",
|
||||
"oe": "s_clkout_enable"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
@@ -571,8 +670,8 @@
|
||||
"pin": 29,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "xpi.nss_o[1]",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [],
|
||||
@@ -584,13 +683,11 @@
|
||||
"pin": 30,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "xpi.nss_o[2]",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [
|
||||
"u_pwm_if.capture_i[0]"
|
||||
],
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
@@ -599,16 +696,22 @@
|
||||
"pin": 31,
|
||||
"alt0": {
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
"do": "xpi.nss_o[3]",
|
||||
"oe": "1'b1"
|
||||
},
|
||||
"alt1": {
|
||||
"inputs": [
|
||||
"u_pwm_if.capture_i[1]"
|
||||
],
|
||||
"inputs": [],
|
||||
"do": "1'b0",
|
||||
"oe": "1'b0"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"dma_request_mask": "0x31ff",
|
||||
"private_crypto": {
|
||||
"banks": 6,
|
||||
"bank_bytes": 4096,
|
||||
"macro_instance": "u_soc.u_crypto.u_storage.gen_bank[{bank}].gen_macro.u_sram.u_mem",
|
||||
"clock_domain": "peripheral",
|
||||
"logical_domain": "PCLK"
|
||||
}
|
||||
}
|
||||
+14
-8
@@ -1,4 +1,5 @@
|
||||
# Both Tiny integrations remain SAFE24; PLL presence is not SYS selection.
|
||||
# Tiny always boots from normalized SAFE24. Dynamic selection is RCU-owned.
|
||||
override TINY_R2_P7 := YES
|
||||
ifneq ($(MINI_MODE),NONE)
|
||||
$(error SOC=TINY requires MINI_MODE=NONE)
|
||||
endif
|
||||
@@ -10,12 +11,12 @@ $(error SOC=TINY requires HAVE_HP=NO)
|
||||
endif
|
||||
ifeq ($(PDK),ICS55)
|
||||
ifneq ($(HAVE_PLL),YES)
|
||||
$(error SOC=TINY PDK=ICS55 requires HAVE_PLL=YES with the PLL held off)
|
||||
$(error SOC=TINY PDK=ICS55 requires HAVE_PLL=YES)
|
||||
endif
|
||||
ifeq ($(PDK_BEHAV),YES)
|
||||
$(error SOC=TINY PDK=ICS55 requires the locked technology models, PDK_BEHAV=NO)
|
||||
endif
|
||||
override TINY_SAFE24_PLL_OFF := YES
|
||||
override TINY_SAFE24_PLL_OFF := NO
|
||||
else
|
||||
ifneq ($(HAVE_PLL),NO)
|
||||
$(error SOC=TINY PDK=IHP130 requires HAVE_PLL=NO)
|
||||
@@ -31,11 +32,16 @@ endif
|
||||
ifneq ($(SRAM_SIZE_KIB),128)
|
||||
$(error SOC=TINY first release requires SRAM_SIZE_KIB=128)
|
||||
endif
|
||||
ifneq ($(EXT_CLK_HZ),24000000)
|
||||
$(error SOC=TINY first release requires EXT_CLK_HZ=24000000)
|
||||
ifeq ($(filter $(EXT_CLK_HZ),24000000 48000000 96000000),)
|
||||
$(error SOC=TINY requires external XIN of 24, 48 or 96 MHz)
|
||||
endif
|
||||
ifneq ($(AUD_CLK_HZ),$(EXT_CLK_HZ))
|
||||
$(error SOC=TINY uses the system clock for RTC and watchdog)
|
||||
ifeq ($(HAVE_PLL),YES)
|
||||
ifneq ($(EXT_CLK_HZ),24000000)
|
||||
$(error SOC=TINY with PLL requires EXT_CLK_HZ=24000000)
|
||||
endif
|
||||
endif
|
||||
ifneq ($(AUD_CLK_HZ),24000000)
|
||||
$(error SOC=TINY RTC and watchdog use normalized REF24)
|
||||
endif
|
||||
ifneq ($(CLINT_TIMEBASE_HZ),1000000)
|
||||
$(error SOC=TINY requires CLINT_TIMEBASE_HZ=1000000)
|
||||
@@ -56,7 +62,7 @@ ifneq ($(ISA),RV32IM)
|
||||
$(error SOC=TINY firmware uses ISA=RV32IM)
|
||||
endif
|
||||
ifneq ($(WS2812_P3_ACCEPTANCE),NO)
|
||||
$(error SOC=TINY does not yet integrate WS2812)
|
||||
$(error SOC=TINY uses its integrated P6 acceptance, not the Mini WS2812 P3 image)
|
||||
endif
|
||||
ifneq ($(filter YES,$(APU_ENABLE_P7) $(NPU_P5_ACCEPTANCE) $(NPU_P6_ACCEPTANCE)),)
|
||||
$(error SOC=TINY does not include multimedia accelerators)
|
||||
|
||||
@@ -205,38 +205,38 @@
|
||||
"jtag_tdi_i_pad": "s_jtag_tdi",
|
||||
"jtag_trst_n_i_pad": "s_jtag_trst_n",
|
||||
"jtag_tdo_o_pad": "s_jtag_tdo",
|
||||
"gpio_0_io_pad": "s_gpio[0]",
|
||||
"gpio_1_io_pad": "s_gpio[1]",
|
||||
"gpio_2_io_pad": "s_gpio[2]",
|
||||
"gpio_3_io_pad": "s_gpio[3]",
|
||||
"gpio_4_io_pad": "s_gpio[4]",
|
||||
"gpio_5_io_pad": "s_gpio[5]",
|
||||
"gpio_6_io_pad": "s_gpio[6]",
|
||||
"gpio_7_io_pad": "s_gpio[7]",
|
||||
"gpio_8_io_pad": "s_gpio[8]",
|
||||
"gpio_9_io_pad": "s_gpio[9]",
|
||||
"gpio_10_io_pad": "s_gpio[10]",
|
||||
"gpio_11_io_pad": "s_gpio[11]",
|
||||
"gpio_12_io_pad": "s_gpio[12]",
|
||||
"gpio_13_io_pad": "s_gpio[13]",
|
||||
"gpio_14_io_pad": "s_gpio[14]",
|
||||
"gpio_15_io_pad": "s_gpio[15]",
|
||||
"gpio_16_io_pad": "s_gpio[16]",
|
||||
"gpio_17_io_pad": "s_gpio[17]",
|
||||
"gpio_18_io_pad": "s_gpio[18]",
|
||||
"gpio_19_io_pad": "s_gpio[19]",
|
||||
"gpio_20_io_pad": "s_gpio[20]",
|
||||
"gpio_21_io_pad": "s_gpio[21]",
|
||||
"gpio_22_io_pad": "s_gpio[22]",
|
||||
"gpio_23_io_pad": "s_gpio[23]",
|
||||
"gpio_24_io_pad": "s_gpio[24]",
|
||||
"gpio_25_io_pad": "s_gpio[25]",
|
||||
"gpio_26_io_pad": "s_gpio[26]",
|
||||
"gpio_27_io_pad": "s_gpio[27]",
|
||||
"gpio_28_io_pad": "s_gpio[28]",
|
||||
"gpio_29_io_pad": "s_gpio[29]",
|
||||
"gpio_30_io_pad": "s_gpio[30]",
|
||||
"gpio_31_io_pad": "s_gpio[31]",
|
||||
"gpio_0_io_pad": "s_gpio_0",
|
||||
"gpio_1_io_pad": "s_gpio_1",
|
||||
"gpio_2_io_pad": "s_gpio_2",
|
||||
"gpio_3_io_pad": "s_gpio_3",
|
||||
"gpio_4_io_pad": "s_gpio_4",
|
||||
"gpio_5_io_pad": "s_gpio_5",
|
||||
"gpio_6_io_pad": "s_gpio_6",
|
||||
"gpio_7_io_pad": "s_gpio_7",
|
||||
"gpio_8_io_pad": "s_gpio_8",
|
||||
"gpio_9_io_pad": "s_gpio_9",
|
||||
"gpio_10_io_pad": "s_gpio_10",
|
||||
"gpio_11_io_pad": "s_gpio_11",
|
||||
"gpio_12_io_pad": "s_gpio_12",
|
||||
"gpio_13_io_pad": "s_gpio_13",
|
||||
"gpio_14_io_pad": "s_gpio_14",
|
||||
"gpio_15_io_pad": "s_gpio_15",
|
||||
"gpio_16_io_pad": "s_gpio_16",
|
||||
"gpio_17_io_pad": "s_gpio_17",
|
||||
"gpio_18_io_pad": "s_gpio_18",
|
||||
"gpio_19_io_pad": "s_gpio_19",
|
||||
"gpio_20_io_pad": "s_gpio_20",
|
||||
"gpio_21_io_pad": "s_gpio_21",
|
||||
"gpio_22_io_pad": "s_gpio_22",
|
||||
"gpio_23_io_pad": "s_gpio_23",
|
||||
"gpio_24_io_pad": "s_gpio_24",
|
||||
"gpio_25_io_pad": "s_gpio_25",
|
||||
"gpio_26_io_pad": "s_gpio_26",
|
||||
"gpio_27_io_pad": "s_gpio_27",
|
||||
"gpio_28_io_pad": "s_gpio_28",
|
||||
"gpio_29_io_pad": "s_gpio_29",
|
||||
"gpio_30_io_pad": "s_gpio_30",
|
||||
"gpio_31_io_pad": "s_gpio_31",
|
||||
"uart0_tx_o_pad": "s_uart0_tx",
|
||||
"uart0_rx_i_pad": "s_uart0_rx",
|
||||
"uart1_tx_o_pad": "s_uart1_tx",
|
||||
@@ -261,38 +261,38 @@
|
||||
"jtag_tdi_i_pad": "s_jtag_tdi",
|
||||
"jtag_trst_n_i_pad": "s_jtag_trst_n",
|
||||
"jtag_tdo_o_pad": "s_jtag_tdo",
|
||||
"gpio_0_io_pad": "s_gpio[0]",
|
||||
"gpio_1_io_pad": "s_gpio[1]",
|
||||
"gpio_2_io_pad": "s_gpio[2]",
|
||||
"gpio_3_io_pad": "s_gpio[3]",
|
||||
"gpio_4_io_pad": "s_gpio[4]",
|
||||
"gpio_5_io_pad": "s_gpio[5]",
|
||||
"gpio_6_io_pad": "s_gpio[6]",
|
||||
"gpio_7_io_pad": "s_gpio[7]",
|
||||
"gpio_8_io_pad": "s_gpio[8]",
|
||||
"gpio_9_io_pad": "s_gpio[9]",
|
||||
"gpio_10_io_pad": "s_gpio[10]",
|
||||
"gpio_11_io_pad": "s_gpio[11]",
|
||||
"gpio_12_io_pad": "s_gpio[12]",
|
||||
"gpio_13_io_pad": "s_gpio[13]",
|
||||
"gpio_14_io_pad": "s_gpio[14]",
|
||||
"gpio_15_io_pad": "s_gpio[15]",
|
||||
"gpio_16_io_pad": "s_gpio[16]",
|
||||
"gpio_17_io_pad": "s_gpio[17]",
|
||||
"gpio_18_io_pad": "s_gpio[18]",
|
||||
"gpio_19_io_pad": "s_gpio[19]",
|
||||
"gpio_20_io_pad": "s_gpio[20]",
|
||||
"gpio_21_io_pad": "s_gpio[21]",
|
||||
"gpio_22_io_pad": "s_gpio[22]",
|
||||
"gpio_23_io_pad": "s_gpio[23]",
|
||||
"gpio_24_io_pad": "s_gpio[24]",
|
||||
"gpio_25_io_pad": "s_gpio[25]",
|
||||
"gpio_26_io_pad": "s_gpio[26]",
|
||||
"gpio_27_io_pad": "s_gpio[27]",
|
||||
"gpio_28_io_pad": "s_gpio[28]",
|
||||
"gpio_29_io_pad": "s_gpio[29]",
|
||||
"gpio_30_io_pad": "s_gpio[30]",
|
||||
"gpio_31_io_pad": "s_gpio[31]",
|
||||
"gpio_0_io_pad": "s_gpio_0",
|
||||
"gpio_1_io_pad": "s_gpio_1",
|
||||
"gpio_2_io_pad": "s_gpio_2",
|
||||
"gpio_3_io_pad": "s_gpio_3",
|
||||
"gpio_4_io_pad": "s_gpio_4",
|
||||
"gpio_5_io_pad": "s_gpio_5",
|
||||
"gpio_6_io_pad": "s_gpio_6",
|
||||
"gpio_7_io_pad": "s_gpio_7",
|
||||
"gpio_8_io_pad": "s_gpio_8",
|
||||
"gpio_9_io_pad": "s_gpio_9",
|
||||
"gpio_10_io_pad": "s_gpio_10",
|
||||
"gpio_11_io_pad": "s_gpio_11",
|
||||
"gpio_12_io_pad": "s_gpio_12",
|
||||
"gpio_13_io_pad": "s_gpio_13",
|
||||
"gpio_14_io_pad": "s_gpio_14",
|
||||
"gpio_15_io_pad": "s_gpio_15",
|
||||
"gpio_16_io_pad": "s_gpio_16",
|
||||
"gpio_17_io_pad": "s_gpio_17",
|
||||
"gpio_18_io_pad": "s_gpio_18",
|
||||
"gpio_19_io_pad": "s_gpio_19",
|
||||
"gpio_20_io_pad": "s_gpio_20",
|
||||
"gpio_21_io_pad": "s_gpio_21",
|
||||
"gpio_22_io_pad": "s_gpio_22",
|
||||
"gpio_23_io_pad": "s_gpio_23",
|
||||
"gpio_24_io_pad": "s_gpio_24",
|
||||
"gpio_25_io_pad": "s_gpio_25",
|
||||
"gpio_26_io_pad": "s_gpio_26",
|
||||
"gpio_27_io_pad": "s_gpio_27",
|
||||
"gpio_28_io_pad": "s_gpio_28",
|
||||
"gpio_29_io_pad": "s_gpio_29",
|
||||
"gpio_30_io_pad": "s_gpio_30",
|
||||
"gpio_31_io_pad": "s_gpio_31",
|
||||
"uart0_tx_o_pad": "s_uart0_tx",
|
||||
"uart0_rx_i_pad": "s_uart0_rx",
|
||||
"uart1_tx_o_pad": "s_uart1_tx",
|
||||
|
||||
+860
-137
File diff suppressed because it is too large.
Load diff
Loaded 100 of 178 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user