基于Sipeed M1s Dock实现的GBA模拟器
实现简易GBA模拟游戏机功能,完成GBA模拟器软件 44VBA 的基础移植。
标签
2023寒假在家练
Sipeed M1s Dock
GBA模拟器
冷月烟
更新2023-03-28
1386

项目介绍

实现简易GBA模拟游戏机功能,完成GBA模拟器软件 44VBA 的基础移植。

设计思路

  • 完成屏幕的基础驱动
  • 完成GBA模拟器软件 44VBA 的基础移植,只移植显示,不移植声音部分
  • 完成物理按键驱动,进行游戏操作,只支持开始键、向左移动键、向右移动键三个按键功能。

GBA模拟器本身包括了解析GBA文件格式、模拟特定GBA机器的cpu指令、内存管理 和 显示引擎的的功能,对于移植来说就是要完成模拟器的接口实现与提供模拟器所需要的资源。

BL808本身就具有高主频与大内存,基本不需要考虑移植时资源的问题,只需要将模拟器提供的接口全部实现即可,其接口主要有:

  1. 按键输入
  2. GBA文件读取
  3. 显示刷新
  4. 声音输出
  5. 错误输出

对于这些接口,本次实现计划:

  1. 使用FatFS文件系统功能加载GBA游戏文件,将读取到的文件加载到模拟器使用的内存里面。
  2. 使用普通按键作为按键输入,对需要的按键初始化,然后把读取的键值输入到模拟器里面。
  3. 使用板载屏幕实现显示功能,GBA模拟器输出图像大小为256*160,板载屏幕为280*240,芯片主频跟spi接口速度也足够,完全可以胜任显示工作。
  4. 因为板子上没有带喇叭,本次移植也就没有移植声音输出功能。

硬件介绍

  • 主芯片 BL808 RISC-V 480Mhz + NPU BLAI-100
  • 板载 USB 转 UART 调试器(可实现一键点击烧录,无需按实体按键)
  • 1.69 寸 240x280 电容触摸屏
  • 200W 像素摄像头
  • 支持 2.4G WIFI / BT / BLE
  • 板载 1 个模拟麦克风、1 个 LED、1 个 TF 卡座
  • 引出一路 USB-OTG 到 USB Type-C 接口

软件介绍

代码流程

  1. 初始化fatfs文件系统。
  2. 配置输入按键,将其初始化为输入、上拉模式。
  3. 初始化LCD显示屏,并清空显示。
  4. 打开文件系统里面存放的gba游戏文件,并将其加载到GBA模拟器运行内存里面。
  5. 运行模拟器。

代码流程图

FlHhVW1E8Rt4roPRJRi3nHjIzHBk

GBA模拟器主要接口量

joy:按键输入量,通过不同的位对应不同的按键,共计有12个,顺序为A, B, SELECT, START, RIGHT, LEFT, UP, DOWN, R, L, TRUBO, MENU

rom:GBA游戏文件加载数组

pix:屏幕显示图像输出数组

GBA 模拟器 44VBA

项目地址:44670/44VBA (github.com)

适用于各种平台的 GBA 模拟器,包括 ESP32-S3、嵌入式 linux、wasm 等。

从 https://github.com/libretro/vba-next 分叉。

游戏下载网站:Gameboy Advance Development (gbadev.org)

主要代码

GBA模拟器接口函数

uint16_t lcd_buff[256 * 160];
uint8_t frameDrawn = 0;

void systemDrawScreen(void)
{
    frameDrawn = 1;

    uint16_t *src = pix;
    uint16_t *dst = lcd_buff;

    for (int y = 0; y < 160; y++) 
    {
        for (int x = 0; x < 256; x++) 
        {
            *dst++ = __builtin_bswap16(*src++);
        }
    }
    st7789v_spi_draw_picture_blocking(20, 40, 20+256-1, 40+160-1, lcd_buff);
}

void systemOnWriteDataToSoundBuffer(int16_t *finalWave, int length) {}

void systemMessage(const char *fmt, ...)
{
    char buf[256];
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    printf("GBA: %s", buf);
}

按键初始化与操作函数

#define KEY_A_PIN (0xff)
#define KEY_B_PIN (0xff)
#define KEY_SELECT_PIN (0xff)
#define KEY_START_PIN (22)
#define KEY_UP_PIN (0xff)
#define KEY_DOWN_PIN (0xff)
#define KEY_LEFT_PIN (23)
#define KEY_RIGHT_PIN (22)
#define KEY_R_PIN (0xff)
#define KEY_L_PIN (0xff)
#define KEY_TRUBO_PIN (0xff)
#define KEY_MENU_PIN (0xff)
uint8_t osKeyMap[12] = {KEY_A_PIN,  KEY_B_PIN,    KEY_SELECT_PIN, KEY_START_PIN, KEY_LEFT_PIN,  KEY_RIGHT_PIN,
                        KEY_UP_PIN, KEY_DOWN_PIN, KEY_R_PIN,      KEY_L_PIN,     KEY_TRUBO_PIN, KEY_MENU_PIN};
uint32_t bl808_key_read()
{
    uint32_t ret = 0;
    for (int i = 0; i < 12; i++) 
    {
        if (osKeyMap[i] != 0xff) 
        {
            int res = GLB_GPIO_Read(osKeyMap[i]);
            if (res == 0) 
            {
                ret |= 1 << i;
            }
        }
    }
    return ret;
}

void bl808_key_init()
{
    GLB_GPIO_Cfg_Type cfg;
    cfg.drive = 0;
    cfg.smtCtrl = 1;
    cfg.gpioFun = GPIO_FUN_GPIO;
    cfg.gpioMode = GPIO_MODE_INPUT;
    cfg.pullType = GPIO_PULL_UP;
    GLB_GPIO_Init(&cfg);
    for (int i = 0; i < 12; i++) 
    {
        cfg.gpioPin = osKeyMap[i];
        if (cfg.gpioPin != 0xff) 
        {
            GLB_GPIO_Input_Enable(cfg.gpioPin);
            GLB_GPIO_Init(&cfg);
        }
    }
}

初始化代码

fatfs_register();
bl808_key_init();
st7789v_spi_init();
st7789v_spi_set_dir(1, 0);
st7789v_spi_clear(0);
emuMainLoop();

模拟器运行

int fd = -1;
fd = aos_open("/flash/goodBoyAdv.gba", 0);
if(fd >= 0)
{
    int model_bin_len = 0;
    model_bin_len = aos_lseek(fd, 0, SEEK_END);
    aos_lseek(fd, 0, SEEK_SET);
    aos_read(fd, rom, model_bin_len);
    aos_close(fd);
}

CPUSetupBuffers();
CPUInit(NULL, false);
CPUReset();
while (1)
{
    joy = bl808_key_read();
    UpdateJoypad();
    frameDrawn = 0;
    while (!frameDrawn) 
    {
        CPULoop();
    }
}

实现的功能及图片展示

开始界面

Fq07bhyTxnw2V_qd7nPFH4zmPwkP

游戏界面

FrAq12a8p5C7eJPMG-Pjd8p3kDRs

游戏操作

FpXcZLRx4gbsE96urvOvBZ_kASFk

遇到的主要难题及解决方法

问题:屏幕输出颜色反转,但图像形状正常

方法:输出颜色的高低位反了,使用__builtin_bswap16调换高低位的位置,显示正常。

问题:测试blai_mnist_demo时,未弹出u盘,教程链接:https://wiki.sipeed.com/hardware/zh/maix/m1s/other/start.html#blai_mnist_demo

方法:使用BLDevCube 软件,完整烧录最新的 boot2, firmware, d0fw 三项。教程链接:https://wiki.sipeed.com/hardware/zh/maix/m1s/other/start.html#%E4%B8%B2%E5%8F%A3%E7%83%A7%E5%BD%95

未来的计划或建议

将这个GBA模拟器移植到其他的单片机板卡上面,设计一个小游戏机,同时支持GBA模拟器跟NES模拟器。最后画一个板子,做成小游戏机的形状。

建议以后多多开展类似的活动。

注意:下载完程序之后,USB接OTG口到电脑,会弹出一个7MB的U盘,将GBA游戏文件拖入U盘根目录下,复位即可(如果要运行其他游戏的话,请修改代码里面的文件路径)

附件下载
play_with_gba.zip
程序
goodBoyAdv.gba
游戏文件
play_with_gba.bin
bin文件
团队介绍
爱摸鱼的工程师
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号