ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

在 Flipper Zero 上跑拓麻歌子 P1 模拟器:ROM 准备、三步部署与 TamaLIB 源码拆解

在 Flipper Zero 上跑拓麻歌子 P1 模拟器:ROM 准备、三步部署与 TamaLIB 源码拆解 在 Flipper Zero 上跑拓麻歌子 P1 模拟器ROM 准备、三步部署与 TamaLIB 源码拆解【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper这个仓库的 tama_p1 目录是一个可以直接编译进固件的插件它在你的 Flipper Zero 上完整模拟一台初代拓麻歌子Tamagotchi P1——包括那颗 4 位的旧芯片、32×16 的黑白小屏、8 个状态小图标还有蜂鸣器。本文带你把 ROM 放对位置、把插件编译部署上设备然后翻开 tama_p1.c 看看它到底是怎么把一台 1996 年的掌机装进STM32 芯片的。让 SD 卡先生出一只 P1 电子宠物上手顺序很简单设备只认 SD 卡上的两个文件你只需要准备对它们。在 microSD 卡根目录建一个tama_p1文件夹把从网络上找到的 P1 ROM 改名为rom.bin丢进这个文件夹。源码里 tama.h 写死了这个路径EXT_PATH(tama_p1/rom.bin)。启动插件后tama_p1.c 的初始化函数会先stat这个文件找不到屏幕直接打印 No ROM 让你自己查找到了整块读进内存然后做一件容易被忽略的事——把字节流重排成半字节流// 每两个字节交换高低位高字节只保留低 4 位 for(size_t i 0; i fi.size; i 2) { uint8_t b ctx-rom[i]; ctx-rom[i] ctx-rom[i 1]; ctx-rom[i 1] b 0xF; }为什么要换因为 P1 的 CPU 一次只算 4 位半个字节程序在芯片里是按半字节排着放的而从 SD 卡读进来的是普通字节流。重排完之后tamalib_init((u12_t*)ctx-rom, NULL, 64000)用 64 kHz 的模拟时钟把虚拟机点着火。另外一个小知识网上流传的这份 ROM最初是从芯片裸片的高清照片里光学识别出来的并不是官方发布的二进制。跑起来之后怎么按基础三键对应 P1 的 A/B/C另外还藏了两个 README 没细说的操作你的操作效果左键 / OK / 右键对应 P1 的 A / B / C 键上键静音源码里同时按下 A C模拟长按消音下键短按立即把当前状态写入存档返回键短按同样触发一次存档长按返回键存档并退出应用注意最后两行README 里那句目前不能存档退出即重置已经过时了。代码里存档功能是实打实写好的退出前会落盘下次启动自动续上机制见下文save.bin 里存了什么。从源码到设备三步完成构建部署如果你只想玩可以跳过这节但如果想让插件出现在自己的固件里流程是这样的。第 1 步搬目录。把这个tama_p1文件夹整体移到固件源码树的applications/plugins/tama_p1这是 Flipper 外部插件的标准位置。第 2 步编译图标。应用引用的 8 个状态小图标要先从 PNG 变成 C 头文件在固件根目录执行scripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled跑完后compiled/下会生成assets_icons.h里面是I_icon_0到I_icon_7的图标数据。第 3 步编译并直接发到设备上。Flipper 固件自带的构建工具fbt有一条launch_app目标能把编译、安装、启动串成一步./fbt launch_app APPSRCapplications/plugins/tama_p1注意官方 README 里写的是反斜杠路径在 Linux 或 macOS 终端里要换成斜杠。如果编译时 TamaLIB 的cpu.c、hw.c报未使用参数类的告警严格告警配置下会当成错误在site_cons/cc.scons的CCFLAGS里加一个-Wno-unused-parameter就能压住。想盯着日志排查的话README 推荐用 FlipperScripts 仓库里的serial_logger.py监听串口应用源码里 ROM 加载、存档读写、输入事件都打了FURI_LOG_D/FURI_LOG_E标签分别是TamaP1和TamaLIB对着串口输出可以很快确认按键映射和状态机有没有按预期走。Flipper Zero 上这类第三方插件游戏不止这一个同一目录下的 Asteroids 就是个参照物——同样是小屏幕、同样靠插件机制加载内核解剖TamaLIB 如何在一颗 STM32 里装下 4 位虚拟机把tama_p1打开看结构是典型的薄壳 内核tamalib/平台无关的模拟核心tamalib/README.md 说明它自底向上实现目标是从微控制器到桌面通吃hal.c不到 150 行的接线板把内核对上 Flipper 的屏幕、时钟、蜂鸣器tama_p1.c应用外壳负责 ROM 加载、事件循环、渲染和存档。先看内核模拟的对象。P1 的芯片是 Epson E0C6S46一颗 4 位 MCU时钟 32,768 Hz。它的内存空间在 cpu.h 里定义得很直白——总共 4096 个 4 位单元其中 RAM 640 个地址0x000~0x27F、两段 LCD 显示区各 80 个0xE00和0xE80起、I/O 寄存器 128 个0xF00~0xF7F。这里有个省内存的设计4096 个半字节如果老老实实占 4 KB对小芯片太奢侈。所以默认打开LOW_FOOTPRINT宏只给真实存在的区域RAM 640 显示 160 I/O 128 个半字节分配约 464 字节的紧凑缓冲每两个半字节打包进一个字节读写时再用移位和掩码拆开。省下来的内存在 STM32WB 上就是实打实的余量。内核和平台之间的接口是一个hal_t结构体hal.c逐个填空几处关键选择值得留意时间源直接用 STM32 的硬件定时器 TIM2初始化时Prescaler 999计数频率约 64 kHz内核问现在几点了就读这个计数器。节奏控制靠sleep_until()当模拟时间还没追上目标时间戳就先放掉互斥锁、让出 1 个 tick 再抢回来——这样虚拟机不会把 CPU 占死也不会越跑越落后。屏幕内核每写一个像素set_lcd_matrix()就把它按位存进一个 16 行的位图每行一个 32 位整数恰好对应 32×16 的屏8 个状态图标则压进 1 个字节的 8 个位里。注意update_screen()是空函数——真正的绘制不归内核管归 GUI 主循环。声音内核报上来的频率要除以 10 才是真实音频频率然后交给furi_hal_speaker驱动内置蜂鸣器。时间戳类型hal_types.h里特意注释timestamp_t必须是无符号 32 位——按微秒计时时它大约每 1 小时 11 分钟回绕一次用有符号类型比较会出错。渲染那端主循环用 30 FPS 的周期定时器触发重绘先把 32×16 的位图按 2 倍放大TAMA_SCREEN_SCALE_FACTOR 2居中画成 64×32 的块再在屏幕上下两侧各排 4 个 14×14 的图标按g_ctx-icons那 8 个位逐一决定亮灭。线程模型也在这层模拟线程只干一件事——循环调用tamalib_step()步进 CPU所以没用它自带的mainloop而是把节奏权交给 GUI 循环它和 GUI 线程之间共享一把递归互斥锁靠一个深度 8 的消息队列传递输入和 Tick 事件互不干扰。application.fam 里的元数据也能印证这是个轻装插件EXTERNAL类型编译成 .fap 从 SD 卡加载、依赖gui和storage两个系统服务、栈只有 1 KB、挂在Games_Extra分类下。save.bin 里存了什么退出后宠物为什么还活着存档文件在/ext/tama_p1/save.bin开头 4 个字节是魔数TLST后面 1 个字节是版本号当前为 2。加载时先校验这两样对不上就记一条 FATAL 日志并跳过恢复——不会拿别人的旧文件硬套。文件剩下的内容就是模拟器的完整快照结构按功能可以归成五组分组内容CPU 状态程序计数器 PC、寄存器 X/Y/A/B、页指针 NP、栈指针 SP、标志位计时tick 计数器、时钟定时器与可编程定时器各自的 4 字节时间戳、定时器使能与数据调用与中断调用栈深度、16 个中断槽每槽 3 字节factor、mask、triggered内存640 字节 RAM每字节存一个半字节、128 字节 I/O 寄存器头部魔数 TLST 版本字节恢复流程是把 PC、寄存器逐字段读回再整块灌回 RAM 和 I/O最后调一次tamalib_refresh_hw()让内核重新同步显示和蜂鸣器的状态。所以长按返回退出、或者干脆把应用杀掉再进来你的宠物都是从上次那个瞬间继续活着不会重新孵蛋。当前边界哪些还没做README 的 To-do 清单很短但足够说明这个版本的轮廓只有单一存档没有多槽位、不能在游戏内软复位宠物、没有测试模式入口、蜂鸣器音量不可调。源码里还能看到加速fast-forward只留了 TODOfast_forward_done被直接置真跳过了。如果你想改按键手感或者加速功能从 tama_p1.c 的输入分支入手想研究 4 位指令集本身cpu.c 就是全部答案。把它跑起来大概需要一张放好rom.bin的 SD 卡一条fbt launch_app命令然后就可以把 1996 年的那只小电子宠物养在口袋设备里了。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表