两处此前**只能靠上板才能排除**的风险,改成结构上不需要排除。
## 1) yield/抢占的软中断:`CTLR/SR.SWIE` → `SWI_IRQn=14`
依据:官方 CH583/CH572 的 FreeRTOS / RT-Thread / HarmonyOS 移植**一处都没用 SWIE**
(SDK 里只定义、零使用;CH572 的 `SysTick_SR_SWIE` 全 SDK 零处调用),yield 一律
`PFIC_SetPendingIRQ(SWI_IRQn)` + `SW_Handler`。
实现:`irq()` 置 `PFIC->IPSR[0] @0xE000E200` bit14;`disable_irq()` 用 `IPRR[0]
@0xE000E280` 清 pending(取中断一般已自动清,防御性再清一次,防残留 pending 让
trap 出口立刻重入);`_start_trap` 的 `_int_dispatch` 增一条 `mcause=14` → 直接进
切换/恢复路径(不做时间账)。初始化不再有"别设 SWIE"的隐含注意事项。
## 2) `delay_us` 的时基:`mcycle` → SysTick 自由计数
依据:"CH583/CH572 是否实现 Zicntr"没有一手证据,未实现时 `mcycle` 读出恒为常量
→ 原实现**死循环**(只能上板发现);SysTick 是内核点拍赖以工作的外设,必然实现。
实现:按 `CMP` 重装周期分块等待,跨重装的差值用模运算;纯算术抽到 `src/chip/delay.rs`
并配 6 项 host 单测。**单测当场抓到一个真 bug**:当 `chunk` 等于整周期时,模运算差值最大
只有 `period-1`,"等到 chunk 拍"这个条件永不成立 → `delay_us` 会在计数器恰为 0
(起点落在重装点,很常见)时死循环。已钳到 `period-1`,并加回归断言
`chunk_never_equals_full_period` 钉住(测试先跑到挂死、杀掉进程后定位)。
## 影响面
只改 ch583 / ch572 两口;ch32v103/ch32v203/ch32v307 仍沿模板的 SWIE 与 `mcycle`
(未在本轮核对它们的 SDK,注释里已标明差异)。
## 验证
- **反汇编核对**:`irq()` = `lui 0xE000E; li 0x4000; sw 0x200`(IPSR bit14);
`switch_context` = `sw 0x280`(IPRR 清 pending);`_int_dispatch` 有 `li t1,0xe` 分支。
- 两口构建 + 启动头产物校验 PASS;`bash ci/gate.sh` 全绿(host 由 159 → **165**,
含新增 6 项;QEMU 三套 24-24、乒乓 A×200 B×200、smp 9-9)。
- 14 口矩阵全绿(esp32c3 已按真 ISA `riscv32imc`);宿主默认 features **88 passed**。
- README 计数快照同步(159→165、82→88)。
## 遗留(仍需上板)
`SWI_IRQn=14` 置 pending 后是否即刻进 trap 并完成切换;`delay_us` 实测精度
(现按 `SYSTICK_CLOCK_HZ` 换算,复位默认主频待实测)。两项都写进了两个口的头注核对清单。
Refs #14
两处此前只能靠上板才能排除的风险,改成结构上不需要排除。
1) yield/抢占的软中断:
CTLR/SR.SWIE→SWI_IRQn=14依据:官方 CH583/CH572 的 FreeRTOS / RT-Thread / HarmonyOS 移植一处都没用 SWIE
(SDK 里只定义、零使用;CH572 的
SysTick_SR_SWIE全 SDK 零处调用),yield 一律PFIC_SetPendingIRQ(SWI_IRQn)+SW_Handler。实现:
irq()置PFIC->IPSR[0] @0xE000E200bit14;disable_irq()用IPRR[0] @0xE000E280清 pending(取中断一般已自动清,防御性再清一次,防残留 pending 让trap 出口立刻重入);
_start_trap的_int_dispatch增一条mcause=14→ 直接进切换/恢复路径(不做时间账)。初始化不再有"别设 SWIE"的隐含注意事项。
2)
delay_us的时基:mcycle→ SysTick 自由计数依据:"CH583/CH572 是否实现 Zicntr"没有一手证据,未实现时
mcycle读出恒为常量→ 原实现死循环(只能上板发现);SysTick 是内核点拍赖以工作的外设,必然实现。
实现:按
CMP重装周期分块等待,跨重装的差值用模运算;纯算术抽到src/chip/delay.rs并配 host 单测。单测当场抓到一个真 bug:当
chunk等于整周期时,模运算差值最大只有
period-1,"等到 chunk 拍"这个条件永不成立 →delay_us会在计数器恰为 0(起点落在重装点,很常见)时死循环。已钳到
period-1,并加回归断言chunk_never_equals_full_period钉住(测试先跑到挂死、杀掉进程后定位)。影响面
只改 ch583 / ch572 两口;ch32v103/ch32v203/ch32v307 仍沿模板的 SWIE 与
mcycle(未在本轮核对它们的 SDK,注释里已标明差异)。
验证
irq()=lui 0xE000E; li 0x4000; sw 0x200(IPSR bit14);switch_context=sw 0x280(IPRR 清 pending);_int_dispatch有li t1,0xe分支。bash ci/gate.sh全绿(host 由 159 → 166,含 chip::delay 的 5 项 + chip::wch_pfic 的 2 项;QEMU 三套 24-24、乒乓 A×200 B×200、smp 9-9)。
riscv32imc);宿主默认 features 89 passed。审查整改(2026-09-19:独立审查 1 处阻塞,已整改并复验)
阻塞项:yield 改走
SWI_IRQn=14后只置了 pending(IPSR[0]bit14),两口的setup_intrrupt()里IENR[0]仍只写1<<12(SysTick)——PFIC 的 pending 与 enable是两组分离的寄存器,没人使能的 pending 永远不会被取走 →
irq()静默失效(yield/抢占只剩 tick 兜底),而构建/门禁/host 测试全绿。官方
port.c的vPortSetupTimerInterrupt()里
PFIC_EnableIRQ(SWI_IRQn)正对应这一步:只抄PFIC_SetPendingIRQ不算移植完成。整改(
539416e):IENR[0]写值1<<12→bit12|bit14;掩码与 PFIC 偏移收进src/chip/wch_pfic.rs单一来源,配 2 项 host 守卫(使能掩码须含 SWI 位、偏移等于官方布局)。
llvm-objdump,两侧镜像):IENR(offset0x100)立即数0x1000→0x5000;IPSR(0x200)/IPRR(0x280) 的0x4000写与_int_dispatch的li t1,0xe分支仍在。chip::wch_pfic::tests::ienr_mask_enables_swi_alongside_systickFAILED(exit 1),已还原。
#[test](同一用例被注册两次,"新增 6 项"由此而来)已去重;两个示例上板清单⑦由"
mcycle是否实现"改为"delay_us实测精度",并给delay_us写明"SysTick 已在跑"的前置条件。
遗留(仍需上板)
SWI_IRQn=14置 pending 后是否即刻进 trap 并完成切换;delay_us实测精度(现按
SYSTICK_CLOCK_HZ换算,复位默认主频待实测)。两项都写进了两个口的头注核对清单。Refs #14