EK-RE01 256KBでGBエミュレータを動かしてみた

# RE01にGBエミュレータを移植してみた話
EK-RE01 256KBにはMIP-LCD基板が付属しています。
MIP-LCD基板を接続するとRE01 256KB内蔵のSPIを使用して画像や文字を表示できます。
今回はRE01にGitHub上で公開されているGBエミュレータを移植してみます。
そして、GBエミュレータの描画結果をMIP-LCDに表示させてみることにします。

# GitHub上で公開されているGBエミュレータ
GitHub上で公開されているCで記述されたGBエミュレータを探してみました。
結果、koenkさんが公開しているGBCが良さそうなので、これを使用させていただきます。
（koenkさんGBCをGitHub上に公開していただきありがとうございました！）

ソースコードの内容を確認するとファイルシステムが使われているみたいです。
なので、インターネット上でChaNさんが公開しているFatFsをRE01 256KBに移植してみました。
しかし、RE01 256KBにはRAMが128KBしか実装されていません。
内蔵RAMだけでファイルシステムを使うためにはこの容量は十分とは言えません。

なので方針を変更しました。
ファイルシステムを使わずにRAM使用量を削減できるようにソースコードを変更します。

# RAM使用量を削減するためにしたこと
### カートリッジROMはRAMにコピーせずにROMに配置したまま使用
GBCでは、エミュレータを動かす際に使用するカートリッジROM等はRAMにコピーします。
このままだとRAM使用量を圧迫してしまうので、ROMに配置したまま使用します。
state.cのstate_new_from_rom関数の内容を以下のように変更しました。

```c:state.c
s->mem_ROM = rom;
s->mem_WRAM = malloc(WRAM_BANKSIZE * s->mem_num_banks_wram);
if (s->mem_num_banks_extram)
    s->mem_EXTRAM = malloc(EXTRAM_BANKSIZE * s->mem_num_banks_extram);
s->mem_VRAM = malloc(VRAM_BANKSIZE * s->mem_num_banks_vram);
```

また、state.cのstate_add_biosの内容も以下のように変更しました。

```c:state.c
void state_add_bios(struct gb_state *s, u8 *bios, size_t bios_size) {
    assert(bios_size == 256);
    s->mem_BIOS = bios;
    s->in_bios = 1;
    s->pc = 0;
}
```

### RAMにコピーする関数の削減
CMSIS Driverの各ドライバ関数の一部はプログラムをRAMに展開する仕様になっています。
今回はRAMに展開したプログラムで動作させる必要はありません。
なので、RAMに展開しないようにコンフィグ設定ファイルを変更しました。

```c:r_adc_cfg.h
#define S14AD_CFG_R_ADC_OPEN            (SYSTEM_SECTION_CODE)     ///<R_ADC_Open() section
#define S14AD_CFG_R_ADC_SCAN_SET        (SYSTEM_SECTION_CODE)     ///<R_ADC_ScanSet() section
#define S14AD_CFG_R_ADC_START           (SYSTEM_SECTION_CODE)     ///<R_ADC_Start() section
#define S14AD_CFG_R_ADC_STOP            (SYSTEM_SECTION_CODE)     ///<R_ADC_Stop() section
```

### MIP-LCDで表示させるためのコードの追加
これはRAM使用量削減とは関係ないですが、MIP-LCDで表示させるためにコードを追加しました。
GBエミュレータの表示処理はsdl.cにあります。
ここにMIP-LCDに画像データを送信する処理を追加しました。

```c
uint8_t disp_copy[(GB_LCD_WIDTH / 8) + 1];
uint8_t display_img[(SMIP_CFG_KYOCERA_DISP_LINE * SMIP_CFG_KYOCERA_DISP_WIDTH) / 8]    = {0};

memset(&disp_copy, 0x00, sizeof(disp_copy));
for (int x = 0; x < lcd_width; x++)
{
    int idx = x + y * lcd_width;
    pixels[idx] = palette[pixbuf[idx]];
    if ((0xffffffff == pixels[idx]) || (0xaaaaaaaa == pixels[idx]))
    {
        disp_copy[x / 8] = disp_copy[x /8] | (1 << (7 - (x % 8)));
    }
}

memcpy(
	&display_img[((y * 256) / 8)
	        + (((SMIP_CFG_KYOCERA_DISP_WIDTH - GB_LCD_WIDTH) / 2)
		        / 8)
	        + (((SMIP_CFG_KYOCERA_DISP_LINE - GB_LCD_HEIGHT) / 2)
	                (SMIP_CFG_KYOCERA_DISP_WIDTH / 8))],
	&disp_copy, sizeof(disp_copy));

result = R_SMIP_Send(((SMIP_CFG_KYOCERA_DISP_LINE - GB_LCD_HEIGHT) / 2 ), GB_LCD_HEIGHT, &display_img[0]);
```
#プログラムの実行
作成したGBエミュレータを実行してみます。
今回はフリーで公開されている20Y (GB Demo)をカートリッジとして使用させて頂きました。
メモリー使用量を見るとRAM使用量は94%程度でギリギリ収まっているようです。
プログラムを実行すると20Y (GB Demo)が起動しました。
ただし、FPSは著しく悪いです…これはSPIの通信速度が原因かなと思っています。

![PXL_20210216_172526291.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354472/6b152227-7a65-c69f-7f0c-fec7a0f942da.jpeg)
![PXL_20210216_172630366.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354472/75bbbca2-e267-00ee-1cd8-b8ee21f91e6a.jpeg)

#最後に
今回はRE01 256KBにGBエミュレータを移植して動作させてみました。
最近、RX72N Envision Kitを購入したので、今度はRXファミリに移植して動作させてみたいと思います。