Hotdry.
hardware-emulation

街机麻将硬件逆向工程:FPGA精确仿真与MAME保存策略的技术权衡

深入分析街机麻将专用硬件的逆向工程挑战,探讨FPGA cycle-accurate仿真与软件模拟器的技术权衡,提出完整的硬件状态保存策略与验证方法。

街机麻将作为日本特有的游戏类型,其硬件设计体现了 90 年代街机产业的独特技术路径。与通用 JAMMA 标准不同,麻将街机采用了专用 56 针接口、按键矩阵扫描和非标准音频处理方案。这些技术特性为硬件保存带来了独特的挑战:如何在芯片标签被刮除、文档稀缺的情况下,实现精确的硬件仿真与状态保存?

街机麻将硬件的技术特殊性

非标准接口与按键矩阵

标准 JAMMA 接口提供 4 方向 + 3 按钮的配置,而麻将游戏需要至少 19 个专用按钮(A-N 字母键 + 5 个呼叫键)。为解决这一矛盾,厂商采用了 56 针专用接口,并引入了按键矩阵设计。

如 Nicole Express 在分析《Mirage Youjuu Mahjongden》时指出:"麻将游戏不使用 JAMMA 标准。有几种引脚排列变体,但到 80 年代末期基本稳定在 56 针连接器,类似于 JAMMA 但没有钥匙针。而且引脚布局完全不同!"

矩阵设计通常采用 6×4 或 3×7 布局,通过扫描线减少引脚需求。这种设计带来了两个技术挑战:

  1. 时序敏感性:矩阵扫描需要精确的时序控制,延迟或抖动会导致按键检测失败
  2. 多按键处理:传统设计假设不会同时按下多个按钮,因此缺少防鬼键二极管

音频处理的多样性

音频处理体现了各厂商的技术分歧。Nichibutsu 采用单端输出(一个引脚接扬声器正极,负极接地),而其他厂商使用差分输出(两个引脚分别接扬声器正负极)。这种不一致性要求适配器必须支持两种模式,通常通过跳线或开关实现。

芯片级逆向工程挑战

《Mirage Youjuu Mahjongden》的 PCB 分析揭示了典型的逆向障碍:

  • CPU 识别:64 引脚表面贴装芯片标签被刮除,通过位置和引脚配置推断为 Motorola 68000
  • 音频芯片:两个 OKI M6295 ADPCM 芯片提供 8 通道音频
  • 定制 ASIC:Data East DECO 156 芯片组变体,功能需要逆向推导

FPGA 精确仿真的技术实现

Cycle-Accurate 架构设计

FPGA 仿真的核心优势在于时钟级精确性。对于 Motorola 68000 CPU,需要实现:

  1. 指令流水线:精确模拟预取、解码、执行、写回四个阶段
  2. 总线时序:模拟地址 / 数据总线复用、等待状态插入
  3. 中断处理:7 级中断优先级和自动向量机制
// 简化的68000总线周期状态机
module m68k_bus_fsm (
    input clk,
    input reset,
    output reg [1:0] bus_state
);
    localparam S0 = 2'b00; // 地址输出
    localparam S1 = 2'b01; // 数据建立
    localparam S2 = 2'b10; // 数据采样
    localparam S3 = 2'b11; // 空闲
    
    always @(posedge clk or posedge reset) begin
        if (reset) bus_state <= S0;
        else case (bus_state)
            S0: bus_state <= S1;
            S1: bus_state <= S2;
            S2: bus_state <= S3;
            S3: bus_state <= S0;
        endcase
    end
endmodule

按键矩阵的硬件仿真

矩阵扫描需要精确的时序控制。典型实现包括:

  1. 扫描计数器:6 位计数器循环激活扫描线
  2. 去抖动逻辑:10ms 机械去抖动延迟
  3. 优先级编码:处理同时按键的冲突
module key_matrix_scanner (
    input clk,
    input [5:0] row_select,
    output reg [3:0] col_read,
    input [23:0] key_state
);
    // 6×4矩阵扫描
    always @(posedge clk) begin
        case (row_select)
            6'b000001: col_read <= key_state[3:0];
            6'b000010: col_read <= key_state[7:4];
            6'b000100: col_read <= key_state[11:8];
            6'b001000: col_read <= key_state[15:12];
            6'b010000: col_read <= key_state[19:16];
            6'b100000: col_read <= key_state[23:20];
            default: col_read <= 4'b1111; // 默认高阻
        endcase
    end
endmodule

音频系统的精确仿真

OKI M6295 ADPCM 芯片需要:

  1. ADPCM 解码引擎:实现 4 位差分脉冲编码调制
  2. 采样率控制:支持 4kHz-8kHz 可调采样率
  3. 混合输出:4 通道音频混合与音量控制

软件模拟器(MAME)的技术权衡

架构优势与局限性

MAME 作为软件模拟器,其优势在于:

  1. 开发效率:C++ 实现,调试工具丰富
  2. 可扩展性:易于添加新游戏支持
  3. 状态保存:完整的快照功能

但存在时序精度问题:

  • 指令级仿真:非 cycle-accurate,时序偏差可能累积
  • 中断延迟:软件模拟难以精确重现硬件中断响应时间
  • 音频同步:采样率转换可能引入相位失真

MAME 调试工具链

逆向工程中,MAME 调试器是关键工具:

# 内存搜索与断点设置
find 0,10000,"HIGH SCORE",0
bp 1234,a0 == 0 && a1 == 0
trace game.log,0,{tracelog "PC=%08X ",pc}

# 状态保存与恢复
save state.sav
load state.sav

状态保存机制

MAME 的状态保存包含:

  1. CPU 上下文:所有寄存器、标志位、程序计数器
  2. 内存状态:ROM 校验和验证,RAM 完整转储
  3. 设备状态:定时器、中断控制器、DMA 控制器
  4. 音频状态:当前采样位置、缓冲区内容

硬件状态保存策略

完整状态捕获框架

有效的硬件保存需要多层次状态捕获:

层级 内容 验证方法
静态 ROM 程序代码、图形数据 CRC32/MD5 校验
动态 RAM 游戏状态、变量 差异比较
寄存器 CPU / 外围寄存器 快照对比
时序状态 定时器、计数器 周期计数
音频状态 缓冲区、相位 波形分析

FPGA 保存实现

FPGA 状态保存需要特殊设计:

  1. 扫描链插入:通过 JTAG 接口读取内部寄存器
  2. 内存转储:通过 DMA 控制器批量读取内存
  3. 时序标记:插入时间戳记录状态变化序列
// 状态保存控制器
module state_save_controller (
    input clk,
    input save_trigger,
    output reg [31:0] state_data,
    output reg state_valid
);
    reg [2:0] save_phase;
    reg [15:0] addr_counter;
    
    always @(posedge clk) begin
        if (save_trigger) begin
            case (save_phase)
                0: begin // 保存CPU寄存器
                    state_data <= cpu_reg_file[addr_counter];
                    addr_counter <= addr_counter + 1;
                    if (addr_counter == 16) save_phase <= 1;
                end
                1: begin // 保存内存
                    state_data <= main_ram[addr_counter];
                    addr_counter <= addr_counter + 1;
                    if (addr_counter == 65535) save_phase <= 2;
                end
                // ... 其他状态保存
            endcase
            state_valid <= 1;
        end else begin
            state_valid <= 0;
            save_phase <= 0;
            addr_counter <= 0;
        end
    end
endmodule

验证与完整性检查

状态保存的验证需要:

  1. 黄金参考:原始硬件运行记录作为基准
  2. 差异分析:比较仿真与硬件的关键行为
  3. 边界测试:测试极端条件下的状态一致性

验证指标包括:

  • 指令一致性:执行相同指令序列的寄存器状态
  • 时序准确性:关键操作的时钟周期计数
  • 输出一致性:视频输出像素级比较
  • 音频保真度:采样点幅度与相位误差

技术权衡与选择指南

FPGA vs 软件模拟器决策矩阵

考量因素 FPGA 优势 软件模拟器优势
时序精度 Cycle-accurate 指令级近似
开发成本 高(硬件设计) 低(软件编程)
运行性能 实时硬件速度 依赖主机性能
状态保存 需要专门设计 内置完善支持
可调试性 硬件调试复杂 软件调试方便
兼容性 特定硬件 跨平台支持

实际项目建议

基于项目需求的技术选择:

  1. 学术研究 / 博物馆保存:优先 FPGA 方案

    • 需要最高精度的时间准确性
    • 长期保存的硬件独立性
    • 预算相对充足
  2. 游戏社区 / 爱好者:推荐 MAME 方案

    • 开发资源丰富,社区支持强
    • 易于分发和使用
    • 兼容现有游戏库
  3. 商业再发行:混合方案

    • FPGA 核心确保准确性
    • 软件层提供用户界面和功能扩展
    • 平衡成本与体验

具体实施参数

对于街机麻将硬件保存,建议以下技术参数:

FPGA 实现参数:

  • 主时钟:12.288MHz(兼容多种 68000 变体)
  • 内存接口:16 位数据总线,24 位地址总线
  • 视频输出:240p@60Hz,RGB 24 位色
  • 音频采样:44.1kHz,16 位立体声
  • 状态保存:每帧自动快照,最大 256 个历史状态

软件模拟器优化:

  • 时序补偿:动态调整指令周期计数
  • 缓存优化:预解码常用指令序列
  • 状态压缩:增量式快照存储
  • 验证模式:与 FPGA 参考实现交叉验证

未来展望与挑战

技术发展趋势

  1. AI 辅助逆向工程:机器学习算法识别芯片功能和信号模式
  2. 云仿真平台:基于 Web 的硬件仿真,降低使用门槛
  3. 标准化保存格式:统一的硬件状态描述语言(HSDL)
  4. 3D 扫描与建模:物理 PCB 的数字化保存

持续挑战

  1. 文档稀缺:特别是专用 ASIC 的内部文档
  2. 硬件老化:原始设备损坏导致参考基准丢失
  3. 法律障碍:知识产权保护与保存需求的平衡
  4. 技术传承:老一辈工程师知识的数字化保存

结语

街机麻将硬件的保存不仅是技术挑战,更是文化遗产的保护。FPGA 与软件模拟器各有优势,实际项目中应根据具体需求选择合适的技术路径。无论选择哪种方案,完整的状态保存策略、严格的验证流程和开放的文档共享都是确保长期保存成功的关键。

通过精确的硬件仿真,我们不仅保存了游戏本身,更保存了特定历史时期的技术创新与设计思想。这种技术保存为未来的研究、教育和创新提供了宝贵的基础资源。

资料来源:

  1. Nicole Express - "Playing Arcade Mahjong at Home? Or is it just a Mirage?" (2026)
  2. MAME 官方调试器文档 - 内存指令与状态保存功能
  3. IGS 街机逆向工程系列 - ASIC27 协议分析与反盗版技术
查看归档