cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

libretro.cpp (17679B)


      1/*
      2 * Gearboy - Nintendo Game Boy Emulator
      3 * Copyright (C) 2012  Ignacio Sanchez
      4 * Copyright (C) 2017  Andrés Suárez
      5 * Copyright (C) 2017  Brad Parker
      6
      7 * This program is free software: you can redistribute it and/or modify
      8 * it under the terms of the GNU General Public License as published by
      9 * the Free Software Foundation, either version 3 of the License, or
     10 * any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program.  If not, see http://www.gnu.org/licenses/
     19 *
     20 */
     21
     22#include <stdio.h>
     23#include <stdint.h>
     24#include <stdlib.h>
     25#include <stdarg.h>
     26#include <string.h>
     27#include <math.h>
     28
     29#include <stdio.h>
     30#include "libretro.h"
     31
     32#include "../../src/gearboy.h"
     33
     34#define VIDEO_WIDTH 160
     35#define VIDEO_HEIGHT 144
     36
     37#ifdef _WIN32
     38static const char slash = '\\';
     39#else
     40static const char slash = '/';
     41#endif
     42
     43static u16* gearboy_frame_buf;
     44
     45static struct retro_log_callback logging;
     46static retro_log_printf_t log_cb;
     47static char retro_system_directory[4096];
     48static char retro_game_path[4096];
     49
     50static s16 audio_buf[AUDIO_BUFFER_SIZE];
     51static int audio_sample_count;
     52
     53static bool force_dmg = false;
     54static bool force_gba = false;
     55static bool allow_up_down = false;
     56static bool bootrom_dmg = false;
     57static bool bootrom_gbc = false;
     58static bool libretro_supports_bitmasks;
     59
     60static void fallback_log(enum retro_log_level level, const char *fmt, ...)
     61{
     62    (void)level;
     63    va_list va;
     64    va_start(va, fmt);
     65    vfprintf(stderr, fmt, va);
     66    va_end(va);
     67}
     68
     69static GearboyCore* core;
     70static Cartridge::CartridgeTypes mapper = Cartridge::CartridgeNotSupported;
     71
     72static retro_environment_t environ_cb;
     73
     74static const struct retro_variable vars[] = {
     75    { "gearboy_model", "Game Boy Model (restart); Auto|Game Boy DMG|Game Boy Advance" },
     76    { "gearboy_mapper", "Mapper (restart); Auto|ROM Only|MBC 1|MBC 2|MBC 3|MBC 5|MBC 1 Multicart" },
     77    { "gearboy_palette", "DMG Palette; Original|Sharp|B/W|Autumn|Soft|Slime" },
     78    { "gearboy_bootrom_dmg", "DMG Bootrom (restart); Disabled|Enabled" },
     79    { "gearboy_bootrom_gbc", "Game Boy Color Bootrom (restart); Disabled|Enabled" },
     80    { "gearboy_up_down_allowed", "Allow Up+Down / Left+Right; Disabled|Enabled" },
     81
     82    { NULL }
     83};
     84
     85// red, green, blue
     86static GB_Color original_palette[4] = {{0x87, 0x96, 0x03},{0x4D, 0x6B, 0x03},{0x2B, 0x55, 0x03},{0x14, 0x44, 0x03}};
     87static GB_Color sharp_palette[4] = {{0xF5, 0xFA, 0xEF},{0x86, 0xC2, 0x70},{0x2F, 0x69, 0x57},{0x0B, 0x19, 0x20}};
     88static GB_Color bw_palette[4] = {{0xFF, 0xFF, 0xFF},{0xAA, 0xAA, 0xAA},{0x55, 0x55, 0x55},{0x00, 0x00, 0x00}};
     89static GB_Color autumn_palette[4] = {{0xF8, 0xE8, 0xC8},{0xD8, 0x90, 0x48},{0xA8, 0x34, 0x20},{0x30, 0x18, 0x50}};
     90static GB_Color soft_palette[4] = {{0xE0, 0xE0, 0xAA},{0xB0, 0xB8, 0x7C},{0x72, 0x82, 0x5B},{0x39, 0x34, 0x17}};
     91static GB_Color slime_palette[4] = {{0xD4, 0xEB, 0xA5},{0x62, 0xB8, 0x7C},{0x27, 0x76, 0x5D},{0x1D, 0x39, 0x39}};
     92
     93static GB_Color* current_palette = original_palette;
     94
     95void retro_init(void)
     96{
     97    const char *dir = NULL;
     98
     99    if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir) {
    100        snprintf(retro_system_directory, sizeof(retro_system_directory), "%s", dir);
    101    }
    102    else {
    103        snprintf(retro_system_directory, sizeof(retro_system_directory), "%s", ".");
    104    }
    105
    106    core = new GearboyCore();
    107
    108#ifdef PS2
    109    core->Init(GB_PIXEL_BGR555);
    110#else
    111    core->Init(GB_PIXEL_RGB565);
    112#endif
    113
    114    gearboy_frame_buf = new u16[VIDEO_WIDTH * VIDEO_HEIGHT];
    115
    116    audio_sample_count = 0;
    117    libretro_supports_bitmasks = environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL);
    118}
    119
    120void retro_deinit(void)
    121{
    122    SafeDeleteArray(gearboy_frame_buf);
    123    SafeDelete(core);
    124}
    125
    126unsigned retro_api_version(void)
    127{
    128    return RETRO_API_VERSION;
    129}
    130
    131void retro_set_controller_port_device(unsigned port, unsigned device)
    132{
    133    log_cb(RETRO_LOG_INFO, "Plugging device %u into port %u.\n", device, port);
    134}
    135
    136void retro_get_system_info(struct retro_system_info *info)
    137{
    138    memset(info, 0, sizeof(*info));
    139    info->library_name     = GEARBOY_TITLE;
    140    info->library_version  = GEARBOY_VERSION;
    141    info->need_fullpath    = false;
    142    info->valid_extensions = "gb|dmg|gbc|cgb|sgb";
    143}
    144
    145static retro_video_refresh_t video_cb;
    146static retro_audio_sample_t audio_cb;
    147static retro_audio_sample_batch_t audio_batch_cb;
    148static retro_input_poll_t input_poll_cb;
    149static retro_input_state_t input_state_cb;
    150
    151void retro_get_system_av_info(struct retro_system_av_info *info)
    152{
    153    float aspect                = (float)VIDEO_WIDTH/VIDEO_HEIGHT;
    154    info->geometry.base_width   = VIDEO_WIDTH;
    155    info->geometry.base_height  = VIDEO_HEIGHT;
    156    info->geometry.max_width    = VIDEO_WIDTH;
    157    info->geometry.max_height   = VIDEO_HEIGHT;
    158    info->geometry.aspect_ratio = aspect;
    159    info->timing.fps            = 4194304.0 / 70224.0;
    160    info->timing.sample_rate    = 44100.0f;
    161}
    162
    163void retro_set_environment(retro_environment_t cb)
    164{
    165    environ_cb = cb;
    166
    167    if (cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging))
    168        log_cb = logging.log;
    169    else
    170        log_cb = fallback_log;
    171
    172    static const struct retro_controller_description controllers[] = {
    173        { "Nintendo Gameboy", RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) },
    174    };
    175
    176    static const struct retro_controller_info ports[] = {
    177        { controllers, 1 },
    178        { NULL, 0 },
    179    };
    180
    181    cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
    182
    183    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars);
    184}
    185
    186void retro_set_audio_sample(retro_audio_sample_t cb)
    187{
    188    audio_cb = cb;
    189}
    190
    191void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
    192{
    193    audio_batch_cb = cb;
    194}
    195
    196void retro_set_input_poll(retro_input_poll_t cb)
    197{
    198    input_poll_cb = cb;
    199}
    200
    201void retro_set_input_state(retro_input_state_t cb)
    202{
    203    input_state_cb = cb;
    204}
    205
    206void retro_set_video_refresh(retro_video_refresh_t cb)
    207{
    208    video_cb = cb;
    209}
    210
    211static void load_bootroms(void)
    212{
    213    char bootrom_dmg_path[4112];
    214    char bootrom_gbc_path[4112];
    215
    216    sprintf(bootrom_dmg_path, "%s%cdmg_boot.bin", retro_system_directory, slash);
    217    sprintf(bootrom_gbc_path, "%s%ccgb_boot.bin", retro_system_directory, slash);
    218
    219    core->GetMemory()->LoadBootromDMG(bootrom_dmg_path);
    220    core->GetMemory()->LoadBootromGBC(bootrom_gbc_path);
    221    core->GetMemory()->EnableBootromDMG(bootrom_dmg);
    222    core->GetMemory()->EnableBootromGBC(bootrom_gbc);
    223}
    224
    225static void update_input(void)
    226{
    227    input_poll_cb();
    228
    229    int16_t ib;
    230    if (libretro_supports_bitmasks)
    231        ib = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
    232    else
    233    {
    234        unsigned int i;
    235        ib = 0;
    236        for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++)
    237            ib |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0;
    238    }
    239
    240    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_UP))
    241    {
    242        if (allow_up_down || !(ib & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)))
    243            core->KeyPressed(Up_Key);
    244    }
    245    else
    246        core->KeyReleased(Up_Key);
    247
    248    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN))
    249    {
    250        if (allow_up_down || !(ib & (1 << RETRO_DEVICE_ID_JOYPAD_UP)))
    251            core->KeyPressed(Down_Key);
    252    }
    253    else
    254        core->KeyReleased(Down_Key);
    255
    256    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT))
    257    {
    258        if (allow_up_down || !(ib & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)))
    259            core->KeyPressed(Left_Key);
    260    }
    261    else
    262        core->KeyReleased(Left_Key);
    263
    264    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT))
    265    {
    266        if (allow_up_down || !(ib & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)))
    267            core->KeyPressed(Right_Key);
    268    }
    269    else
    270        core->KeyReleased(Right_Key);
    271
    272    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_B))
    273        core->KeyPressed(B_Key);
    274    else
    275        core->KeyReleased(B_Key);
    276    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_A))
    277        core->KeyPressed(A_Key);
    278    else
    279        core->KeyReleased(A_Key);
    280    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_START))
    281        core->KeyPressed(Start_Key);
    282    else
    283        core->KeyReleased(Start_Key);
    284    if (ib & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT))
    285        core->KeyPressed(Select_Key);
    286    else
    287        core->KeyReleased(Select_Key);
    288}
    289
    290static void check_variables(void)
    291{
    292    struct retro_variable var = {0};
    293
    294    var.key = "gearboy_model";
    295    var.value = NULL;
    296
    297    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    298    {
    299        if (strcmp(var.value, "Game Boy DMG") == 0)
    300        {
    301            force_dmg = true;
    302            force_gba = false;
    303        }
    304        else if (strcmp(var.value, "Game Boy Advance") == 0)
    305        {
    306            force_gba = true;
    307            force_dmg = false;
    308        }
    309        else
    310        {
    311            force_dmg = false;
    312            force_gba = false;
    313        }
    314    }
    315
    316    var.key = "gearboy_mapper";
    317    var.value = NULL;
    318
    319    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    320    {
    321        if (strcmp(var.value, "Auto") == 0)
    322            mapper = Cartridge::CartridgeNotSupported;
    323        else if (strcmp(var.value, "ROM Only") == 0)
    324            mapper = Cartridge::CartridgeNoMBC;
    325        else if (strcmp(var.value, "MBC 1") == 0)
    326            mapper = Cartridge::CartridgeMBC1;
    327        else if (strcmp(var.value, "MBC 2") == 0)
    328            mapper = Cartridge::CartridgeMBC2;
    329        else if (strcmp(var.value, "MBC 3") == 0)
    330            mapper = Cartridge::CartridgeMBC3;
    331        else if (strcmp(var.value, "MBC 5") == 0)
    332            mapper = Cartridge::CartridgeMBC5;
    333        else if (strcmp(var.value, "MBC 1 Multicart") == 0)
    334            mapper = Cartridge::CartridgeMBC1Multi;
    335        else
    336            mapper = Cartridge::CartridgeNotSupported;
    337    }
    338
    339    var.key = "gearboy_palette";
    340    var.value = NULL;
    341
    342    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    343    {
    344        if (strcmp(var.value, "Original") == 0)
    345            current_palette = original_palette;
    346        else if (strcmp(var.value, "Sharp") == 0)
    347            current_palette = sharp_palette;
    348        else if (strcmp(var.value, "B/W") == 0)
    349            current_palette = bw_palette;
    350        else if (strcmp(var.value, "Autumn") == 0)
    351            current_palette = autumn_palette;
    352        else if (strcmp(var.value, "Soft") == 0)
    353            current_palette = soft_palette;
    354        else if (strcmp(var.value, "Slime") == 0)
    355            current_palette = slime_palette;
    356        else
    357            current_palette = original_palette;
    358    }
    359
    360    var.key = "gearboy_bootrom_dmg";
    361    var.value = NULL;
    362
    363    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    364    {
    365        if (strcmp(var.value, "Enabled") == 0)
    366            bootrom_dmg = true;
    367        else
    368            bootrom_dmg = false;
    369    }
    370
    371    var.key = "gearboy_bootrom_gbc";
    372    var.value = NULL;
    373
    374    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    375    {
    376        if (strcmp(var.value, "Enabled") == 0)
    377            bootrom_gbc = true;
    378        else
    379            bootrom_gbc = false;
    380    }
    381
    382    var.key = "gearboy_up_down_allowed";
    383    var.value = NULL;
    384
    385    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    386    {
    387        if (strcmp(var.value, "Enabled") == 0)
    388            allow_up_down = true;
    389        else
    390            allow_up_down = false;
    391    }
    392}
    393
    394void retro_run(void)
    395{
    396    bool updated = false;
    397    if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
    398    {
    399        check_variables();
    400        core->SetDMGPalette(current_palette[0], current_palette[1], current_palette[2], current_palette[3]);
    401    }
    402
    403    update_input();
    404
    405    core->RunToVBlank(gearboy_frame_buf, audio_buf, &audio_sample_count);
    406
    407    video_cb((uint8_t*)gearboy_frame_buf, VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_WIDTH * sizeof(u16));
    408
    409    if (audio_sample_count > 0)
    410        audio_batch_cb(audio_buf, audio_sample_count / 2);
    411
    412    audio_sample_count = 0;
    413}
    414
    415void retro_reset(void)
    416{
    417    check_variables();
    418    load_bootroms();
    419
    420    core->SetDMGPalette(current_palette[0], current_palette[1], current_palette[2], current_palette[3]);
    421
    422    core->ResetROMPreservingRAM(force_dmg, mapper, force_gba);
    423}
    424
    425
    426bool retro_load_game(const struct retro_game_info *info)
    427{
    428    check_variables();
    429    load_bootroms();
    430
    431    core->SetDMGPalette(current_palette[0], current_palette[1], current_palette[2], current_palette[3]);
    432
    433    if (!core->LoadROMFromBuffer(reinterpret_cast<const u8*>(info->data), info->size, force_dmg, mapper, force_gba))
    434    {
    435        log_cb(RETRO_LOG_ERROR, "Invalid or corrupted ROM.\n");
    436        return false;
    437    }
    438
    439    struct retro_input_descriptor desc[] = {
    440        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "Left" },
    441        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "Up" },
    442        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "Down" },
    443        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "Right" },
    444        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
    445        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
    446        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
    447        { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
    448        { 0 },
    449    };
    450
    451    environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
    452
    453    enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
    454    
    455    if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
    456    {
    457        log_cb(RETRO_LOG_INFO, "RETRO_PIXEL_FORMAT_RGB565 is not supported.\n");
    458        return false;
    459    }
    460
    461    snprintf(retro_game_path, sizeof(retro_game_path), "%s", info->path);
    462
    463    struct retro_memory_descriptor descs[11];
    464
    465    memset(descs, 0, sizeof(descs));
    466
    467    // IE
    468    descs[0].ptr   = core->GetMemory()->GetMemoryMap() + 0xFFFF;
    469    descs[0].start = 0xFFFF;
    470    descs[0].len   = 1;
    471    // HRAM
    472    descs[1].ptr   = core->GetMemory()->GetMemoryMap() + 0xFF80;
    473    descs[1].start = 0xFF80;
    474    descs[1].len   = 0x0080;
    475    // RAM bank 0
    476    descs[2].ptr   = core->IsCGB() ? core->GetMemory()->GetCGBRAM() : (core->GetMemory()->GetMemoryMap() + 0xC000);
    477    descs[2].start = 0xC000;
    478    descs[2].len   = 0x1000;
    479    // RAM bank 1
    480    descs[3].ptr   = core->IsCGB() ? (core->GetMemory()->GetCGBRAM() + (0x1000)) : (core->GetMemory()->GetMemoryMap() + 0xD000);
    481    descs[3].start = 0xD000;
    482    descs[3].len   = 0x1000;
    483    // CART RAM
    484    descs[4].ptr   = core->GetMemory()->GetCurrentRule()->GetCurrentRamBank();
    485    descs[4].start = 0xA000;
    486    descs[4].len   = 0x2000;
    487    // VRAM
    488    descs[5].ptr   = core->GetMemory()->GetMemoryMap() + 0x8000; // todo: fix GBC
    489    descs[5].start = 0x8000;
    490    descs[5].len   = 0x2000;
    491    // ROM bank 0
    492    descs[6].ptr   = core->GetMemory()->GetCurrentRule()->GetRomBank0();
    493    descs[6].start = 0x0000;
    494    descs[6].len   = 0x4000;
    495    // ROM bank x
    496    descs[7].ptr   = core->GetMemory()->GetCurrentRule()->GetCurrentRomBank1();
    497    descs[7].start = 0x4000;
    498    descs[7].len   = 0x4000;
    499    // OAM
    500    descs[8].ptr   = core->GetMemory()->GetMemoryMap() + 0xFE00;
    501    descs[8].start = 0xFE00;
    502    descs[8].len   = 0x00A0;
    503    descs[8].select= 0xFFFFFF00;
    504    // CGB RAM banks 2-7
    505    descs[9].ptr   = core->IsCGB() ? (core->GetMemory()->GetCGBRAM() + 0x2000) : (core->GetMemory()->GetMemoryMap() + 0xD000);
    506    descs[9].start = 0x10000;
    507    descs[9].len   = core->IsCGB() ? 0x6000 : 0;
    508    descs[9].select= 0xFFFF0000;
    509    // IO PORTS
    510    descs[10].ptr   = core->GetMemory()->GetMemoryMap() + 0xFF00;
    511    descs[10].start = 0xFF00;
    512    descs[10].len   = 0x0080;
    513    descs[10].select= 0xFFFFFF00;
    514
    515    struct retro_memory_map mmaps;
    516    mmaps.descriptors = descs;
    517    mmaps.num_descriptors = sizeof(descs) / sizeof(descs[0]);
    518    environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &mmaps);
    519
    520    bool achievements = true;
    521    environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &achievements);
    522
    523    return true;
    524}
    525
    526void retro_unload_game(void)
    527{
    528}
    529
    530unsigned retro_get_region(void)
    531{
    532    return RETRO_REGION_NTSC;
    533}
    534
    535bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num)
    536{
    537    return false;
    538}
    539
    540size_t retro_serialize_size(void)
    541{
    542    size_t size;
    543    core->SaveState(NULL, size);
    544    return size;
    545}
    546
    547bool retro_serialize(void *data, size_t size)
    548{
    549    return core->SaveState(reinterpret_cast<u8*>(data), size);
    550}
    551
    552bool retro_unserialize(const void *data, size_t size)
    553{
    554    return core->LoadState(reinterpret_cast<const u8*>(data), size);
    555}
    556
    557void *retro_get_memory_data(unsigned id)
    558{
    559    switch (id)
    560    {
    561        case RETRO_MEMORY_SAVE_RAM:
    562            return core->GetMemory()->GetCurrentRule()->GetRamBanks();
    563        case RETRO_MEMORY_RTC:
    564            return core->GetMemory()->GetCurrentRule()->GetRTCMemory();
    565        case RETRO_MEMORY_SYSTEM_RAM:
    566            return core->IsCGB() ? core->GetMemory()->GetCGBRAM() : core->GetMemory()->GetMemoryMap() + 0xC000;
    567    }
    568
    569    return NULL;
    570}
    571
    572size_t retro_get_memory_size(unsigned id)
    573{
    574    switch (id)
    575    {
    576        case RETRO_MEMORY_SAVE_RAM:
    577           return core->GetMemory()->GetCurrentRule()->GetRamSize();
    578        case RETRO_MEMORY_RTC:
    579           return core->GetMemory()->GetCurrentRule()->GetRTCSize();
    580        case RETRO_MEMORY_SYSTEM_RAM:
    581           return core->IsCGB() ? 0x8000 : 0x2000;
    582    }
    583
    584    return 0;
    585}
    586
    587void retro_cheat_reset(void)
    588{
    589    core->ClearCheats();
    590}
    591
    592void retro_cheat_set(unsigned index, bool enabled, const char *code)
    593{
    594    core->SetCheat(code);
    595}