Skip to content

feature: tamcpp examples runnable - #13

Merged
Charliechen114514 merged 14 commits into
mainfrom
feat/run-tamcpp-samples
Jul 11, 2026
Merged

feature: tamcpp examples runnable#13
Charliechen114514 merged 14 commits into
mainfrom
feat/run-tamcpp-samples

Conversation

@Charliechen114514

Copy link
Copy Markdown
Member

欸超了,发现没JIT被做局了,LED 例子搞不通,上大的!

A1 spike(加载 TAMCPP 1_led_control 的 C++ elf 看 PC13 toggle)暴露两个被
现有 busy-loop delay_ms 样例掩盖的 bug:

1. elf_loader .data 段按 p_vaddr 加载,漏了 flash LMA 副本。裸机 startup 的
   CopyDataInit 从 _sidata(=p_paddr)复制 .data 到 SRAM,但 LMA 未加载→
   读 0→SystemCoreClock 被清零→HAL_InitTick 的 SYSTICK_Config(0) 走 ERROR
   不配 SysTick→HAL_Delay 死循环。改按 p_paddr 加载(p_paddr!=0 且 !=p_vaddr
   时),初值落 flash LMA 让 CopyDataInit 复制,与真实烧录器行为一致;.text
   段 p_vaddr==p_paddr 无变化。补 test_elf_loader:
   DataSegmentLoadedToFlashLmaWhenVaddrDiffers。

2. cortex_m3 线程模式 active_preempt=preempt_priority(0xFF),4 位截断成 0xF,
   与最低优先级 exception(SysTick 默认 0xF0→0xF)相等,严格 < 不成立→
   SysTick 不抢占线程→HAL_IncTick 不调→uwTick 不涨。改线程模式用 0xFF(不
   截断),任何 exception preempt(0..0xF)均 < 0xFF 可抢占;handler 模式
   nesting 不变,NVIC E2E 不破坏。

新增 examples/tamcpp_blink/ runner(spike 验证工具,elf 由外部脚本编出暂不
进 ctest;A2 串口打通时再正规化 firmware build)。

ctest 368/368 绿(含新 LMA 测试 + NVIC E2E 不破坏);spike 实测 PC13
toggle=1>0,C++ HAL 样例首次在模拟器跑通。
HAL_NVIC_SetPriority 用 strb 写 IP[IRQn],原 write 只支持 Word 返回
Unaligned → DataAccessFault。IPR 分支提前 + 按 width 更新对应字节,
ISER/ICER/ISPR/ICPR 仍 Word。TAMCPP 3_uart_logger enable_interrupt 因此通。
build_sample.sh 参数化编 TAMCPP 1/2/3 C++ elf(借 STM32CubeF1,不改 TAMCPP)。
TAMCPP_ROOT cache 变量不进 git。led spike 通(PC13 toggle=1),uart TX 通
('UART Logger Ready!'),uart RX 收命令(回 ERR,链路通),button spike
诊断中(poll_events 去抖状态机卡)。加 -std=c++23(uart_driver std::expected)。
记录 elf_loader .data LMA + SysTick 优先级 + nvic IPR 字节写三 bug;
led/uart TX/收命令 通;button poll_events 去抖卡(诊断中);firmware CMake
正规化。runner 加 last_fault/mmio_trace 诊断。
IT 指令(0xBF1x) mask 解码 1u<<(3-slot) 取 mask[3-slot],但 ARM 编码
slot i 的 THEN/ELSE 位是 mask[4-i](slot1→mask[3])。itt ne(mask=0xC)
和 ite ne(mask=0x4) 的 mask[2] 都是 1,旧代码无法区分,导致 ite 的
ELSE 槽用 THEN 条件执行。

实际影响:HAL_GPIO_ReadPin 的 `ite ne; movne r0,#1; moveq r0,#0`
两个 mov 都执行,r0 被 moveq 覆盖=0,ReadPin 永远返回 0(无论 IDR=0/1)。
TAMCPP 2_button_control 因此一直认为按下。

修复:3-slot → 4-slot。编码验证:
  itt ne=0xBF1C → slot1 mask[3]=1==1 THEN  → [ne,ne]
  ite ne=0xBF14 → slot1 mask[3]=0≠1   ELSE → [ne,eq]
  itee ne=0xBF12 → [ne,eq,eq]

ctest 368/368 绿。button on() 修复后在 press 段触发(ReadPin=0 正确)。
IT 块条件存在独立的 it_conditions_,SysTick 打断 HAL_GPIO_ReadPin
的 ITE 块时 handler 消费线程条件、异常返回也不恢复——IDR 恒 1 但
ReadPin 偶发返回 0,每次假按下重置 release 去抖,2_button_control
的 off() 永不触发。

异常 entry 按嵌套层级把 (it_conditions_, it_condition_pos_) 压入
suspended_it_states_ 并清空(handler 起点在 IT 块之外),return 弹出
恢复到被打断的槽位。新增 ExceptionPreservesInterruptedItBlock 回归
测试。runner_button 验证 on=1 off=1 [PASS]。ctest 369 绿。
POP {pc} 弹出 EXC_RETURN 时,write_pc 触发 interrupt_return(从 SP
弹 8 字异常帧并恢复 SP);但 t16_pop 随后用局部 sp(尚未 +4)writeback,
覆盖了 interrupt_return 刚恢复的 SP → 每次 exception 净漏 0x20。

3_uart_logger 的 USART1 RXNE 中断每收一字节 sp 偏 0x20 → line_buf
(@sp+16)地址漂移 → strb 写错位置 → handle_command 的 cmd=="LED ON"
比较恒失败 → 回 ERR: unknown command。SysTick handler 走 bx lr 不经
pop {pc},故此前一直平衡、未暴露本题。

修:pop {pc} 先 writeback sp+4、再 write_pc,让 interrupt_return 从
正确位置弹帧。runner_uart 验证 TX banner=1 RX cmd=1。notes 044 记第
6 个模拟器 bug + led/button/uart 三样例全通。
仿 hal_uart E2E 模式(E2E_TAMCPP_*_ELF 宏 + #ifdef TEST):
- TamcppLed:1_led_control PC13 toggle(while 里 HAL_Delay(500) 间 on/off,
  run 80M cycles 观察首次 on)。
- TamcppButton:2_button_control 注入 PA0 idle→press→release,验 PC13 BSRR
  reset/set 各触发一次(覆盖 IT block mask + ITSTATE 异常保存)。
- TamcppUart:3_uart_logger 注入 RX "LED ON\r\n",验 TX banner + RX 回
  "OK: LED ON"(覆盖 pop{pc} SP 正确恢复)。

需 TAMCPP_ROOT + STM32CubeF1 双门禁(tamcpp_*_firmware target 存在)。
ctest 372 绿(+3)。
3 样例全通 + 6 bug 修完 + E2E.Tamcpp{Led,Button,Uart} 进 ctest(372 绿)。
MainWindow:
- setAcceptDrops + dragEnterEvent/dropEvent:拖 .elf/.bin 到窗口即加载
- File 菜单 Open(Ctrl+O,QFileDialog):拖拽之外的另一入口
- loadFirmware 复用 reset 的 stop-timer + rebuild 路径

GpioPanel:加回 PA0 push-button(checkable,active-low:hold=press 低,
release=idle 高)→ injectGpio 信号 → session.simulate_gpio_input。原 A2
按钮被移除是因 demo 固件不读 IDR,但 TAMCPP 2_button_control 的
HAL_GPIO_ReadPin 读 IDR,对它有效。

配合线 B 的 serial_panel RX 输入框 + 板视图 PC13 QuarkBulb,TAMCPP 三
样例可加载进 GUI:LED(PC13)/ button(PA0 按/放)/ uart(TX banner + RX
输入 "LED ON" 回 "OK: LED ON")。offscreen smoke 验证不崩。
原 inputSubmitted 只注入用户打的字节("LED ON"),固件 handle_command
要等 \r/\n 才触发,所以 GUI 输入命令没回复。且连续 inject_rx 多字节,
USART 的 DR 是单字节缓冲,没中间 run 会覆盖丢字节。

改:每字节 inject 后 session_.run(50000) 让 RXNE IRQ 消费该字节,结尾
追加 \r\n 触发固件行解析。
@Charliechen114514
Charliechen114514 merged commit 6deb0e5 into main Jul 11, 2026
2 checks passed
@Charliechen114514
Charliechen114514 deleted the feat/run-tamcpp-samples branch July 11, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant