把拓麻歌子 P1 塞进 Flipper Zero:从 ROM 到按键的完整上手指南 把拓麻歌子 P1 塞进 Flipper Zero从 ROM 到按键的完整上手指南【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper一块 32×16 像素的黑白屏里跑着整台 4 位掌机——更夸张的是这台掌机的 ROM 最初是从芯片裸片的高清照片上一个比特一个比特光学识读出来的。现在它正跑在你的 Flipper Zero 上Tama P1 Emulator基于 TamaLIB 的拓麻歌子初代模拟器就是这样一个 EXTERNAL 插件源码位于仓库的 Applications/Official/source-OLDER/xMasterX/tama_p1。读完这篇你能把 ROM 放对位置、把 .fap 构建部署上机并看懂它模拟 4 位 CPU 的每个关键决策。先看它跑起来屏幕上会发生什么这一节先立预期装好之后你看到和摸到的是什么。正常运行的画面32×16 的像素矩阵被 2 倍放大成 64×32 的色块居中绘制矩阵上下各排 4 枚 14×14 的状态图标共 8 枚按内部位图逐位显隐。两个兜底提示ROM 文件没放对屏幕只会显示 No ROM模拟 CPU 运行中触发 halt则显示 Halted。按键手感三个基础键对应拓麻歌子的 A/B/C另外藏着两个 README 没细说的功能——左键 → Tamagotchi A 键OK 键 → B 键右键 → C 键长按返回键 → 保存并退出应用上键 → 静音同时向模拟内核上报左、右两个按键的按下/释放等效于原机的 AC 组合短按 Down 或短按返回键 → 立刻把当前状态写进存档静音和随手存都藏在源码的输入分支里上键同时调用两次tamalib_set_button而 Down/Back 的短按直接触发存档函数。开跑之前的准备ROM 只有一个合法名字这一节只回答一个问题上机前 SD 卡上要放什么、放哪。在 microSD 卡上建一个tama_p1目录即/ext/tama_p1。上网搜索 Tamagotchi P1 的 ROM。原 README 的说法是搜到一个叫a的文件它本身就是 ROM重命名为rom.bin即可。文件最终落在/ext/tama_p1/rom.bin。这个路径由 tama.h 里的TAMA_ROM_PATHEXT_PATH(tama_p1/rom.bin)写死改名或挪窝都会直接落到 No ROM。加载后还有一步不可见的字节序重排别指望 ROM 是原样可读的P1 的 CPU 是 4 位机程序按半字节nibble组织。加载代码每两个字节交换一次并把换出来的高字节只保留低 4 位b 0xF把字节流重排成模拟内核认识的半字节序列。从源码到能玩两条命令的最短路径这一节解决怎么把插件构建成 .fap 并直接跑起来。按真实执行顺序来把整个tama_p1文件夹放进固件源码树的applications/plugins/tama_p1。依次执行下面的命令scripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled ./fbt launch_app APPSRCapplications/plugins/tama_p1第一条把icons/下 8 个状态图标 PNG 编译成 C 头文件产物是 compiled/assets_icons.h里面声明I_icon_0到I_icon_7供绘制回调引用第二条一步完成编译、部署到设备并立即启动APPSRC指向插件目录。注意原 README 写的是反斜杠路径applications\plugins\tama_p1在 Linux Shell 里必须换成斜杠即上式写法。如果编译因未使用参数告警而失败把-Wno-unused-parameter追加进 site_cons/cc.scons 的CCFLAGS——TamaLIB 的cpu.c、hw.c会触发这类告警。应用身份写 application.famappid 为TAMA_P1入口函数tama_p1_app依赖gui与storage两个系统服务线程栈 1 KB上架分类Games_Extra图标tamaIcon.png。收尾排错出问题就挂串口日志。FlipperScripts 里有个serial_logger.py单独跑python serial_logger.py可以持续监听也可以和启动命令用分号连成一条应用一起动日志就跟上。源码里有两个日志 Tag 值得盯TamaP1ROM 加载、存档读写、以及每次按键的 sequence/key/type 三要素和TamaLIB模拟内核内部。它是怎么模拟出一台 4 位掌机的模拟内核E0C6S46 的 4096 个半字节TamaLIB 是从零写的硬件无关模拟库目标是从 MCU 一直跑上桌面。它模拟的对象是Epson E0C6S46 4 位 MCU主频 32,768 Hz屏幕 32×16 黑白加 8 个状态图标——也就是拓麻歌子 P1 的全部硬件假设。地址空间总大小MEMORY_SIZE 40964096 个 4 位单元四段划分RAM0x000–0x27F640 个半字节显示区 10xE00–0xE4F80 个半字节显示区 20xE80–0xECF80 个半字节I/O0xF00–0xF7F128 个半字节默认开启LOW_FOOTPRINT宏后这 928 个半字节被两两打包进约 464 字节的连续缓冲用SET_RAM_MEMORY/GET_RAM_MEMORY一类宏按位读写——对 STM32WB 这种 RAM 寸土寸金的环境省下的是一整块 4 KB。标准用法是注册 HAL →tamalib_init(program, bps, freq)→ 主循环 → 释放四步freq参数决定时间戳的单位刻度。本项目取了更灵活的路不起tamalib_mainloop()而是开一个独立线程循环调tamalib_step()线程栈 1 KB名叫 TamaLIBfreq传 64000把模拟节奏完全交还给 Flipper 的 GUI 事件循环。HAL 对接TIM2 计时、蜂鸣器与帧缓冲TamaLIB 通过hal_t结构体把平台依赖全部外抛内存分配、halt 回调、日志、时钟、屏幕、声音。hal.c 不到两百行把每一项落到 Flipper 硬件上时间拿硬件定时器 TIM2 当模拟时间源。初始化时Prescaler 999计数频率约 64 kHzget_timestamp()直接读LL_TIM_GetCounter(TIM2)。sleep_until()是节奏核心——发现模拟时间落后于目标戳时先释放互斥锁、furi_delay_tick(1)让出 CPU再抢回锁继续步进。屏幕set_lcd_matrix(x, y, val)把模拟器逐像素的写操作转存进framebuffer[16]——一行一个uint32_t一个 bit 一个像素set_lcd_icon()则在icons这个字节上置/清位。真正的上屏由 GUI 主循环负责所以update_screen()是空实现。声音set_frequency把上报值除以 10freq / 10.0换算成实际频率play_frequency通过furi_hal_speaker_acquire/start/stop驱动内置蜂鸣器。halt模拟 CPU 停机时置位halted界面随即切到 Halted。hal_types.h 里有个容易忽略的约束timestamp_t必须是无符号类型——以微秒计时时32 位无符号数约 1 小时 11 分钟就会自然回绕有符号类型会让时间比较直接出错。渲染节奏与 save.bin 的二进制布局刷新由一个 30 FPS 周期定时器驱动周期 内核 tick 频率 ÷ 30每次 Tick 事件触发view_port_update()。绘制回调先以 25 tick 超时抢锁与模拟线程同步然后按 2 倍因子把 32×16 矩阵放大居中再依据g_ctx-icons的 8 个位在矩阵上下两侧均分位置逐枚画 14×14 图标。模拟线程与 GUI 线程靠一把递归互斥锁和 8 深度的FuriMessageQueue传EventTypeInput/EventTypeTick两类事件协同。存档有一处文档矛盾结论是它真的能存。README 前文写着目前无存档退出即重置但同一份 README 的 Implemented 一节又列着 Saving/Loading emulator state (stored in/ext/tama_p1/save.bin)而源码里加载与写档函数完整存在长按返回退出时写盘启动时自动恢复。判定为前文是过时描述存档功能以源码行为为准。写盘与读盘共用同一份二进制布局读档时先校验文件头再逐字段恢复最后调tamalib_refresh_hw()让显示和蜂鸣器重新同步字段说明TLST4 字节魔数合法性校验不匹配则记 FATAL 并放弃恢复21 字节版本号PC2 字节程序计数器高字节掩码 0x1F共 12 位X / Y各 2 字节通用寄存器高字节掩码 0xFA / B / NP / SP / Flags各 1 字节累加器、B 寄存器取低 4 位、页选择低 5 位、栈指针、标志三个时间戳类计数器tick_counter、时钟定时器戳、可编程定时器戳各 4 字节定时器控制使能位、数据、重装载值各 1 字节call_depth4 字节调用栈深度16 × 3 字节16 个中断槽的 factor/mask/triggeredRAM640 字节每个半字节独占 1 字节I/O128 字节对应0xF00–0xF7F边界与取舍五件没做完的事这些是 README To-do 清单上明牌挂着的缺口每条附一句为什么现状说得过去Slots多存档槽目前只有一个save.bin。合理——单槽让魔数版本号的校验路径保持最简扩槽位时格式机制可直接复用。In-game reset游戏内重置不退出应用就无法软复位。合理——复位入口不在 4 位机固件暴露的常规操作里属于锦上添花而非玩法刚需。Test mode测试模式固件自带自检模式的入口尚未打通。合理——自检对养宠物这条主线无直接影响。Volume adjustment音量调节蜂鸣器音量不可调。合理——扬声器 HAL 只关心频率使能音量属于平台层参数。Fast-forward加速源码里fast_forward_done被直接置真旁边挂着TODO: implement fast forwarding。合理——加速涉及模拟时钟缩放做坏了会破坏存档里的时间戳一致性留到有把握再动。把rom.bin放进 SD 卡、跑一次那条launch_app命令这只 4 位虚拟宠物就从上次退出的那一秒继续活着。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考