From b15411dad864413d62ea6c479b902ef072c0001f Mon Sep 17 00:00:00 2001
From: Jamiras <jamirasmt@gmail.com>
Date: Thu, 16 Jul 2020 13:35:34 -0600
Subject: [PATCH 1/4] generic memory mapping using rcheevos

---
 Makefile.common                          |   2 +-
 cheevos/cheevos.c                        | 117 +++-----
 cheevos/cheevos.h                        |   4 +-
 cheevos/fixup.c                          | 314 ---------------------
 cheevos/memory.c                         | 340 +++++++++++++++++++++++
 cheevos/{fixup.h => memory.h}            |  29 +-
 deps/rcheevos/src/rcheevos/consoleinfo.c |   2 +-
 griffin/griffin.c                        |   2 +-
 retroarch.c                              |  12 +-
 9 files changed, 410 insertions(+), 412 deletions(-)
 delete mode 100644 cheevos/fixup.c
 create mode 100644 cheevos/memory.c
 rename cheevos/{fixup.h => memory.h} (62%)

diff --git a/Makefile.common b/Makefile.common
index cdcab25402..60e1d844df 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -1952,7 +1952,7 @@ ifeq ($(HAVE_NETWORKING), 1)
 
       OBJ += cheevos/cheevos.o \
              cheevos/badges.o \
-             cheevos/fixup.o \
+             cheevos/memory.o \
              cheevos/parser.o \
              cheevos/hash.o \
              $(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c
index 435fa3ea26..239727f385 100644
--- a/cheevos/cheevos.c
+++ b/cheevos/cheevos.c
@@ -52,7 +52,7 @@
 
 #include "badges.h"
 #include "cheevos.h"
-#include "fixup.h"
+#include "memory.h"
 #include "parser.h"
 #include "hash.h"
 #include "util.h"
@@ -79,9 +79,6 @@
 /* Define this macro to prevent cheevos from being deactivated. */
 #undef CHEEVOS_DONT_DEACTIVATE
 
-/* Define this macro to dump all cheevos' addresses. */
-#undef CHEEVOS_DUMP_ADDRS
-
 /* Define this macro to load a JSON file from disk instead of downloading
  * from retroachievements.org. */
 #undef CHEEVOS_JSON_OVERRIDE
@@ -166,7 +163,7 @@ typedef struct
    rcheevos_lboard_t* lboards;
    rcheevos_richpresence_t richpresence;
 
-   rcheevos_fixups_t fixups;
+   rcheevos_memory_regions_t memory;
 
    char token[32];
    char hash[33];
@@ -185,7 +182,7 @@ static rcheevos_locals_t rcheevos_locals =
    NULL, /* unofficial */
    NULL, /* lboards */
    {0},  /* rich presence */
-   {0},  /* fixups */
+   {{0}},/* memory */
    {0},  /* token */
    "N/A",/* hash */
 };
@@ -377,31 +374,29 @@ static void rcheevos_log_post_url(
 #endif
 }
 
+uint8_t* rcheevos_patch_address(unsigned address)
+{
+   return rcheevos_memory_find(&rcheevos_locals.memory, address);
+}
+
 static unsigned rcheevos_peek(unsigned address, unsigned num_bytes, void* ud)
 {
-   const uint8_t* data = rcheevos_fixup_find(&rcheevos_locals.fixups,
-      address, rcheevos_locals.patchdata.console_id);
-   unsigned      value = 0;
-
-   if (data)
+   uint8_t* data = rcheevos_memory_find(&rcheevos_locals.memory, address);
+   if (data != NULL)
    {
       switch (num_bytes)
       {
-         case 4:
-            value |= data[2] << 16 | data[3] << 24;
-         case 2:
-            value |= data[1] << 8;
-         case 1:
-            value |= data[0];
+      case 4: return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0]);
+      case 3: return (data[2] << 16) | (data[1] << 8) | (data[0]);
+      case 2: return (data[1] << 8) | (data[0]);
+      case 1: return data[0];
       }
    }
-   else
-      rcheevos_locals.invalid_peek_address = true;
 
-   return value;
+   rcheevos_locals.invalid_peek_address = true;
+   return 0;
 }
 
-
 static void rcheevos_async_award_achievement(rcheevos_async_io_request* request);
 static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request);
 
@@ -564,8 +559,6 @@ static int rcheevos_parse(const char* json)
    rcheevos_lboard_t* lboard = NULL;
    rcheevos_racheevo_t* rac  = NULL;
 
-   rcheevos_fixup_init(&rcheevos_locals.fixups);
-
    res = rcheevos_get_patchdata(json, &rcheevos_locals.patchdata);
 
    if (res != 0)
@@ -595,52 +588,18 @@ static int rcheevos_parse(const char* json)
       return 0;
    }
 
-   /* Achievement memory accesses are 0-based, regardless of 
-    * where the memory is accessed by the
-    * emulated code. As such, address 0 should always be 
-    * accessible and serves as an indicator that
-    * other addresses will also be accessible. 
-    * Individual achievements will be "Unsupported" if
-    * they contain addresses that cannot be resolved. 
-    * This check gives the user immediate feedback
-    * if the core they're trying to use will disable all 
-    * achievements as "Unsupported".
-    */
-   if (!rcheevos_patch_address(0, rcheevos_locals.patchdata.console_id))
+   if (!rcheevos_memory_init(&rcheevos_locals.memory, rcheevos_locals.patchdata.console_id))
    {
-      int delay_judgment          = 0;
-      rarch_system_info_t* system = runloop_get_system_info();
-
-      if (system->mmaps.num_descriptors == 0)
+      /* some cores (like Mupen64-Plus) don't expose the memory until the first call to retro_run.
+       * in that case, there will be a total_size of memory reported by the core, but init will return
+       * false, as all of the pointers were null.
+       */
+      if (rcheevos_locals.memory.total_size != 0)
       {
-         /* Special case: the mupen64plus-nx core doesn't 
-          * initialize the RAM immediately. To avoid a race
-          * condition - if the core says there's SYSTEM_RAM, 
-          * but the pointer is NULL, proceed. If the memory
-          * isn't exposed when the achievements start processing, 
-          * they'll be marked "Unsupported" individually.
-          */
-         retro_ctx_memory_info_t meminfo;
-         meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
-         core_get_memory(&meminfo);
-
-         delay_judgment |= (meminfo.size > 0);
+         /* reset the memory count and we'll re-evaluate in rcheevos_test() */
+         rcheevos_locals.memory.count = 0;
       }
       else
-      {
-         /* Special case: the sameboy core exposes the RAM 
-          * at $8000, but not the ROM at $0000. NES and
-          * Gameboy achievements do attempt to map the 
-          * entire bus, and it's unlikely that an achievement
-          * will reference the ROM data, so if the RAM is 
-          * still present, allow the core to load. If any
-          * achievements do reference the ROM data, they'll 
-          * be marked "Unsupported" individually.
-          */
-         delay_judgment |= (rcheevos_patch_address(0x8000, rcheevos_locals.patchdata.console_id) != NULL);
-      }
-
-      if (!delay_judgment)
       {
          CHEEVOS_ERR(RCHEEVOS_TAG "No memory exposed by core\n");
 
@@ -802,7 +761,7 @@ error:
    CHEEVOS_FREE(rcheevos_locals.unofficial);
    CHEEVOS_FREE(rcheevos_locals.lboards);
    rcheevos_free_patchdata(&rcheevos_locals.patchdata);
-   rcheevos_fixup_destroy(&rcheevos_locals.fixups);
+   rcheevos_memory_destroy(&rcheevos_locals.memory);
    return -1;
 }
 
@@ -1128,6 +1087,10 @@ void rcheevos_reset_game(void)
    }
 
    rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec();
+
+   /* some cores reallocate memory on reset, make sure we update our pointers */
+   if (rcheevos_locals.memory.total_size > 0)
+      rcheevos_memory_init(&rcheevos_locals.memory, rcheevos_locals.patchdata.console_id);
 }
 
 #ifdef HAVE_MENU
@@ -1348,7 +1311,7 @@ bool rcheevos_unload(void)
       CHEEVOS_FREE(rcheevos_locals.lboards);
       CHEEVOS_FREE(rcheevos_locals.richpresence.richpresence);
       rcheevos_free_patchdata(&rcheevos_locals.patchdata);
-      rcheevos_fixup_destroy(&rcheevos_locals.fixups);
+      rcheevos_memory_destroy(&rcheevos_locals.memory);
 
       rcheevos_locals.core                      = NULL;
       rcheevos_locals.unofficial                = NULL;
@@ -1411,6 +1374,21 @@ void rcheevos_test(void)
 {
    settings_t *settings = config_get_ptr();
 
+   if (rcheevos_locals.memory.count == 0)
+   {
+      /* we were unable to initialize memory earlier, try now */
+      if (!rcheevos_memory_init(&rcheevos_locals.memory, rcheevos_locals.patchdata.console_id))
+      {
+         CHEEVOS_ERR(RCHEEVOS_TAG "No memory exposed by core\n");
+
+         if (settings->bools.cheevos_verbose_enable)
+            runloop_msg_queue_push("Cannot activate achievements using this core.", 0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
+
+         rcheevos_loaded = false;
+         return;
+      }
+   }
+
    rcheevos_test_cheevo_set(true);
 
    if (settings)
@@ -1435,11 +1413,6 @@ bool rcheevos_get_support_cheevos(void)
    return rcheevos_locals.core_supports;
 }
 
-int rcheevos_get_console(void)
-{
-   return rcheevos_locals.patchdata.console_id;
-}
-
 const char* rcheevos_get_hash(void)
 {
    return rcheevos_locals.hash;
diff --git a/cheevos/cheevos.h b/cheevos/cheevos.h
index b1096be9a5..6844bf3a23 100644
--- a/cheevos/cheevos.h
+++ b/cheevos/cheevos.h
@@ -61,12 +61,12 @@ void rcheevos_set_support_cheevos(bool state);
 
 bool rcheevos_get_support_cheevos(void);
 
-int rcheevos_get_console(void);
-
 const char* rcheevos_get_hash(void);
 
 const char *rcheevos_get_richpresence(void);
 
+uint8_t* rcheevos_patch_address(unsigned address);
+
 extern bool rcheevos_loaded;
 extern bool rcheevos_hardcore_active;
 extern bool rcheevos_hardcore_paused;
diff --git a/cheevos/fixup.c b/cheevos/fixup.c
deleted file mode 100644
index 67bc4cf2a7..0000000000
--- a/cheevos/fixup.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*  RetroArch - A frontend for libretro.
- *  Copyright (C) 2015-2018 - Andre Leiradella
- *
- *  RetroArch is free software: you can redistribute it and/or modify it under the terms
- *  of the GNU General Public License as published by the Free Software Found-
- *  ation, either version 3 of the License, or (at your option) any later version.
- *
- *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- *  PURPOSE.  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along with RetroArch.
- *  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "fixup.h"
-#include "cheevos.h"
-#include "util.h"
-
-#include "../retroarch.h"
-#include "../core.h"
-
-#include "../deps/rcheevos/include/rcheevos.h"
-#include "../deps/rcheevos/include/rconsoles.h"
-
-static int rcheevos_cmpaddr(const void* e1, const void* e2)
-{
-   const rcheevos_fixup_t* f1 = (const rcheevos_fixup_t*)e1;
-   const rcheevos_fixup_t* f2 = (const rcheevos_fixup_t*)e2;
-
-   if (f1->address < f2->address)
-      return -1;
-   else if (f1->address > f2->address)
-      return 1;
-   return 0;
-}
-
-static size_t rcheevos_var_reduce(size_t addr, size_t mask)
-{
-   while (mask)
-   {
-      size_t tmp = (mask - 1) & ~mask;
-      addr       = (addr & tmp) | ((addr >> 1) & ~tmp);
-      mask       = (mask & (mask - 1)) >> 1;
-   }
-
-   return addr;
-}
-
-static size_t rcheevos_var_highest_bit(size_t n)
-{
-   n |= n >>  1;
-   n |= n >>  2;
-   n |= n >>  4;
-   n |= n >>  8;
-   n |= n >> 16;
-
-   return n ^ (n >> 1);
-}
-
-void rcheevos_fixup_init(rcheevos_fixups_t* fixups)
-{
-   fixups->elements = NULL;
-   fixups->capacity = fixups->count = 0;
-   fixups->dirty    = false;
-}
-
-void rcheevos_fixup_destroy(rcheevos_fixups_t* fixups)
-{
-   CHEEVOS_FREE(fixups->elements);
-   rcheevos_fixup_init(fixups);
-}
-
-const uint8_t* rcheevos_fixup_find(
-      rcheevos_fixups_t* fixups, unsigned address, int console)
-{
-   rcheevos_fixup_t key;
-   rcheevos_fixup_t* found;
-   const uint8_t* location;
-
-   if (fixups->dirty)
-   {
-      qsort(fixups->elements, fixups->count,
-            sizeof(rcheevos_fixup_t), rcheevos_cmpaddr);
-      fixups->dirty = false;
-   }
-
-   key.address = address;
-   found       = (rcheevos_fixup_t*)bsearch(&key,
-         fixups->elements, fixups->count,
-         sizeof(rcheevos_fixup_t), rcheevos_cmpaddr);
-
-   if (found)
-      return found->location;
-
-   if (fixups->count == fixups->capacity)
-   {
-      unsigned new_capacity = fixups->capacity == 0 ? 16 : fixups->capacity * 2;
-      rcheevos_fixup_t* new_elements = (rcheevos_fixup_t*)
-         realloc(fixups->elements, new_capacity * sizeof(rcheevos_fixup_t));
-
-      if (!new_elements)
-         return NULL;
-
-      fixups->elements = new_elements;
-      fixups->capacity = new_capacity;
-   }
-
-   fixups->elements[fixups->count].address    = address;
-   fixups->elements[fixups->count++].location = location =
-      rcheevos_patch_address(address, console);
-   fixups->dirty                              = true;
-
-   return location;
-}
-
-const uint8_t* rcheevos_patch_address(unsigned address, int console)
-{
-   rarch_system_info_t* system = runloop_get_system_info();
-   const void* pointer         = NULL;
-   unsigned original_address   = address;
-
-   switch (console)
-   {
-      case RC_CONSOLE_NINTENDO:
-         if (address >= 0x0800 && address < 0x2000)
-         {
-            /* Address in the mirrorred RAM, 
-             * adjust to real RAM. */
-            CHEEVOS_LOG(RCHEEVOS_TAG "NES memory address in mirrorred RAM %X, adjusted to %X\n", address, address & 0x07ff);
-            address &= 0x07ff;
-         }
-         break;
-      case RC_CONSOLE_GAMEBOY_COLOR:
-         if (address >= 0xe000 && address <= 0xfdff)
-         {
-            /* Address in the echo RAM, adjust to real RAM. */
-            CHEEVOS_LOG(RCHEEVOS_TAG "GBC memory address in echo RAM %X, adjusted to %X\n", address, address - 0x2000);
-            address -= 0x2000;
-         }
-         break;
-      default:
-         break;
-   }
-
-   if (system->mmaps.num_descriptors != 0)
-   {
-      /* We have memory descriptors, use it. */
-      const rarch_memory_descriptor_t* desc = NULL;
-      const rarch_memory_descriptor_t* end  = NULL;
-
-      /* Patch the address to correctly map it to the mmaps. */
-      switch (console)
-      {
-         case RC_CONSOLE_GAMEBOY_ADVANCE:
-            if (address < 0x8000)
-            {
-               /* Internal RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "GBA memory address %X adjusted to %X\n", address, address + 0x3000000);
-               address += 0x3000000;
-            }
-            else
-            {
-               /* Work RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "GBA memory address %X adjusted to %X\n", address, address + 0x2000000 - 0x8000);
-               address += 0x2000000 - 0x8000;
-            }
-            break;
-         case RC_CONSOLE_PC_ENGINE:
-            if (address < 0x002000)
-            {
-               /* RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "PCE memory address %X adjusted to %X\n", address, address + 0x1f0000);
-               address += 0x1f0000;
-            }
-            else if (address < 0x012000)
-            {
-               /* CD-ROM RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "PCE memory address %X adjusted to %X\n", address, address + 0x100000 - 0x002000);
-               address += 0x100000 - 0x002000;
-            }
-            else if (address < 0x042000)
-            {
-               /* Super System Card RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "PCE memory address %X adjusted to %X\n", address, address + 0x0d0000 - 0x012000);
-               address += 0x0d0000 - 0x012000;
-            }
-            else
-            {
-               /* CD-ROM battery backed RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "PCE memory address %X adjusted to %X\n", address, address + 0x1ee000 - 0x042000);
-               address += 0x1ee000 - 0x042000;
-            }
-            break;
-         case RC_CONSOLE_SUPER_NINTENDO:
-            if (address < 0x020000)
-            {
-               /* Work RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "SNES memory address %X adjusted to %X\n", address, address + 0x7e0000);
-               address += 0x7e0000;
-            }
-            else
-            {
-               /* Save RAM. */
-               CHEEVOS_LOG(RCHEEVOS_TAG "SNES memory address %X adjusted to %X\n", address, address + 0x006000 - 0x020000);
-               address += 0x006000 - 0x020000;
-            }
-            break;
-         case RC_CONSOLE_SEGA_CD:
-            if (address < 0x010000)
-            {
-               /* Work RAM. */
-               address += 0xFF0000;
-               CHEEVOS_LOG(RCHEEVOS_TAG "Sega CD memory address %X adjusted to %X\n", original_address, address);
-            }
-            else
-            {
-               /* CD-ROM peripheral RAM - exposed at virtual address to avoid banking */
-               address += 0x80020000 - 0x010000;
-               CHEEVOS_LOG(RCHEEVOS_TAG "Sega CD memory address %X adjusted to %X\n", original_address, address);
-            }
-            break;
-         default:
-            break;
-      }
-
-      desc = system->mmaps.descriptors;
-      end  = desc + system->mmaps.num_descriptors;
-
-      for (; desc < end; desc++)
-      {
-         if (((desc->core.start ^ address) & desc->core.select) == 0)
-         {
-            pointer = desc->core.ptr;
-            address -= desc->core.start;
-
-            if (desc->disconnect_mask)
-               address = (unsigned)rcheevos_var_reduce(
-                     address & desc->disconnect_mask, desc->core.disconnect);
-
-            if (address >= desc->core.len)
-               address -= rcheevos_var_highest_bit(address);
-
-            address += desc->core.offset;
-
-            CHEEVOS_LOG(RCHEEVOS_TAG "address %X set to descriptor %d at offset %X\n", original_address,
-                  (int)((desc - system->mmaps.descriptors) + 1), address);
-            break;
-         }
-      }
-   }
-   else if (console == RC_CONSOLE_GAMEBOY_ADVANCE)
-   {
-      /* The RetroAchievements implementation of memory access 
-       * for GBA puts the save RAM first,
-       * so the default looping behavior below is backwards. 
-       *
-       * If the core doesn't expose a
-       * memory map, say it isn't supported.
-       */
-       pointer = NULL;
-   }
-   else
-   {
-      unsigned i;
-
-      for (i = 0; i < 4; i++)
-      {
-         retro_ctx_memory_info_t meminfo;
-
-         switch (i)
-         {
-            case 0:
-               meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
-               break;
-            case 1:
-               meminfo.id = RETRO_MEMORY_SAVE_RAM;
-               break;
-            case 2:
-               meminfo.id = RETRO_MEMORY_VIDEO_RAM;
-               break;
-            case 3:
-               meminfo.id = RETRO_MEMORY_RTC;
-               break;
-         }
-
-         core_get_memory(&meminfo);
-
-         if (address < meminfo.size)
-         {
-            pointer = meminfo.data;
-            break;
-         }
-
-         /**
-          * HACK Subtract the correct amount of bytes to 
-          * reach the save RAM as its size is not always 
-          * set correctly in the core.
-          */
-         if (i == 0 && console == RC_CONSOLE_NINTENDO)
-            address -= 0x6000;
-         else
-            address -= meminfo.size;
-      }
-   }
-
-   if (!pointer)
-   {
-      CHEEVOS_LOG(RCHEEVOS_TAG "address %X not supported\n", original_address);
-      return NULL;
-   }
-
-   return (const uint8_t*)pointer + address;
-}
diff --git a/cheevos/memory.c b/cheevos/memory.c
new file mode 100644
index 0000000000..37e73897ab
--- /dev/null
+++ b/cheevos/memory.c
@@ -0,0 +1,340 @@
+/*  RetroArch - A frontend for libretro.
+ *  Copyright (C) 2015-2016 - Andre Leiradella
+ *
+ *  RetroArch is free software: you can redistribute it and/or modify it under the terms
+ *  of the GNU General Public License as published by the Free Software Found-
+ *  ation, either version 3 of the License, or (at your option) any later version.
+ *
+ *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *  PURPOSE.  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with RetroArch.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "memory.h"
+
+#include "util.h"
+
+#include "../retroarch.h"
+#include "../verbosity.h"
+
+#include "../deps/rcheevos/include/rcheevos.h"
+
+#include <stdio.h>
+
+uint8_t* rcheevos_memory_find(const rcheevos_memory_regions_t* regions, unsigned address)
+{
+   unsigned i;
+
+   for (i = 0; i < regions->count; ++i)
+   {
+      const size_t size = regions->size[i];
+      if (address < size)
+      {
+         if (regions->data[i] == NULL)
+            break;
+
+         return &regions->data[i][address];
+      }
+
+      address -= size;
+   }
+
+   return NULL;
+}
+
+static const char* rcheevos_memory_type(int type)
+{
+   switch (type)
+   {
+   case RC_MEMORY_TYPE_SAVE_RAM: return "SRAM";
+   case RC_MEMORY_TYPE_VIDEO_RAM: return "VRAM";
+   case RC_MEMORY_TYPE_UNUSED: return "UNUSED";
+   default: return "SYSTEM RAM";
+   }
+}
+
+static void rcheevos_memory_register_region(rcheevos_memory_regions_t* regions,
+   int type, uint8_t* data, size_t size, const char* description)
+{
+   if (size == 0)
+      return;
+
+   if (regions->count == MAX_MEMORY_REGIONS)
+   {
+      CHEEVOS_LOG(RCHEEVOS_TAG "Too many memory memory regions to register\n");
+      return;
+   }
+
+   if (!data && regions->count > 0 && !regions->data[regions->count - 1])
+   {
+      /* extend null region */
+      regions->size[regions->count - 1] += size;
+   }
+   else if (data && regions->count > 0 &&
+      data == (regions->data[regions->count - 1] + regions->size[regions->count - 1]))
+   {
+      /* extend non-null region */
+      regions->size[regions->count - 1] += size;
+   }
+   else
+   {
+      /* create new region */
+      regions->data[regions->count] = data;
+      regions->size[regions->count] = size;
+      ++regions->count;
+   }
+
+   regions->total_size += size;
+
+   CHEEVOS_LOG(RCHEEVOS_TAG "Registered 0x%04X bytes of %s at $%06X (%s)\n", size,
+      rcheevos_memory_type(type), regions->total_size - size, description);
+}
+
+static void rcheevos_memory_init_without_regions(rcheevos_memory_regions_t* regions)
+{
+   /* no regions specified, assume system RAM followed by save RAM */
+   char description[64];
+   retro_ctx_memory_info_t meminfo;
+   sprintf(description, "offset 0x%06x", 0);
+
+   meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
+   core_get_memory(&meminfo);
+   rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SYSTEM_RAM, meminfo.data, meminfo.size, description);
+
+   meminfo.id = RETRO_MEMORY_SAVE_RAM;
+   core_get_memory(&meminfo);
+   rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, meminfo.data, meminfo.size, description);
+}
+
+static const rarch_memory_descriptor_t* rcheevos_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned real_address)
+{
+   if (mmap->num_descriptors == 0)
+      return NULL;
+
+   const rarch_memory_descriptor_t* desc = mmap->descriptors;
+   const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
+
+   for (; desc < end; desc++)
+   {
+      if (desc->core.select == 0)
+      {
+         /* if select is 0, attempt to explcitly match the address */
+         if (real_address >= desc->core.start && real_address < desc->core.start + desc->core.len)
+            return desc;
+      }
+      else
+      {
+         /* otherwise, attempt to match the address by matching the select bits */
+         if (((desc->core.start ^ real_address) & desc->core.select) == 0)
+         {
+            /* sanity check - make sure the descriptor is large enough to hold the target address */
+            if (real_address - desc->core.start < desc->core.len)
+               return desc;
+         }
+      }
+   }
+
+   return NULL;
+}
+
+void rcheevos_memory_init_from_memory_map(rcheevos_memory_regions_t* regions, const rarch_memory_map_t* mmap, const rc_memory_regions_t* console_regions)
+{
+   char description[64];
+   unsigned i;
+   uint8_t* region_start;
+   uint8_t* desc_start;
+   size_t desc_size;
+   size_t offset;
+
+   for (i = 0; i < console_regions->num_regions; ++i)
+   {
+      const rc_memory_region_t* console_region = &console_regions->region[i];
+      size_t console_region_size = console_region->end_address - console_region->start_address + 1;
+      unsigned real_address = console_region->real_address;
+
+      while (console_region_size > 0)
+      {
+         const rarch_memory_descriptor_t* desc = rcheevos_memory_get_descriptor(mmap, real_address);
+         if (!desc)
+         {
+            if (console_region->type != RC_MEMORY_TYPE_UNUSED)
+            {
+               CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n",
+                  real_address - console_region->real_address + console_region->start_address);
+            }
+
+            rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
+            break;
+         }
+
+         offset = real_address - desc->core.start;
+         sprintf(description, "descriptor %u, offset 0x%06X", (int)(desc - mmap->descriptors) + 1, (int)offset);
+
+         if (desc->core.ptr)
+         {
+            desc_start = (uint8_t*)desc->core.ptr + desc->core.offset;
+            region_start = desc_start + offset;
+         }
+         else
+         {
+            region_start = NULL;
+         }
+
+         desc_size = desc->core.len - offset;
+
+         if (console_region_size > desc_size)
+         {
+            if (desc_size == 0)
+            {
+               if (console_region->type != RC_MEMORY_TYPE_UNUSED)
+               {
+                  CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n",
+                     real_address - console_region->real_address + console_region->start_address);
+               }
+
+               rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
+               console_region_size = 0;
+            }
+            else
+            {
+               rcheevos_memory_register_region(regions, console_region->type, region_start, desc_size, description);
+               console_region_size -= desc_size;
+               real_address += desc_size;
+            }
+         }
+         else
+         {
+            rcheevos_memory_register_region(regions, console_region->type, region_start, console_region_size, description);
+            console_region_size = 0;
+         }
+      }
+   }
+}
+
+static unsigned rcheevos_memory_console_region_to_ram_type(int region_type)
+{
+   switch (region_type)
+   {
+   case RC_MEMORY_TYPE_SAVE_RAM:
+      return RETRO_MEMORY_SAVE_RAM;
+   case RC_MEMORY_TYPE_VIDEO_RAM:
+      return RETRO_MEMORY_VIDEO_RAM;
+   default:
+      return RETRO_MEMORY_SYSTEM_RAM;
+   }
+}
+
+static void rcheevos_memory_init_from_unmapped_memory(rcheevos_memory_regions_t* regions, const rc_memory_regions_t* console_regions, int console)
+{
+   char description[64];
+   unsigned i;
+
+   for (i = 0; i < console_regions->num_regions; ++i)
+   {
+      const rc_memory_region_t* console_region = &console_regions->region[i];
+      const size_t console_region_size = console_region->end_address - console_region->start_address + 1;
+      retro_ctx_memory_info_t meminfo;
+      size_t offset;
+      unsigned base_address = 0;
+      unsigned j;
+
+      meminfo.id = rcheevos_memory_console_region_to_ram_type(console_region->type);
+
+      for (j = 0; j <= i; ++j)
+      {
+         const rc_memory_region_t* console_region2 = &console_regions->region[j];
+         if (rcheevos_memory_console_region_to_ram_type(console_region2->type) == meminfo.id)
+         {
+            base_address = console_region2->start_address;
+            break;
+         }
+      }
+      offset = console_region->start_address - base_address;
+
+      core_get_memory(&meminfo);
+
+      if (offset < meminfo.size)
+      {
+         meminfo.size -= offset;
+
+         if (meminfo.data != NULL)
+         {
+            sprintf(description, "offset 0x%06X", (int)offset);
+            meminfo.data = (uint8_t*)meminfo.data + offset;
+         }
+         else
+         {
+            sprintf(description, "null filler");
+         }
+      }
+      else
+      {
+         if (console_region->type != RC_MEMORY_TYPE_UNUSED)
+         {
+            CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n", console_region->start_address);
+         }
+
+         meminfo.data = NULL;
+         meminfo.size = 0;
+      }
+
+      if (console_region_size > meminfo.size)
+      {
+         /* want more than what is available, take what we can and null fill the rest */
+         rcheevos_memory_register_region(regions, console_region->type, meminfo.data, meminfo.size, description);
+         rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size - meminfo.size, "null filler");
+      }
+      else
+      {
+         /* only take as much as we need */
+         rcheevos_memory_register_region(regions, console_region->type, meminfo.data, console_region_size, description);
+      }
+   }
+}
+
+void rcheevos_memory_destroy(rcheevos_memory_regions_t* regions)
+{
+   memset(regions, 0, sizeof(*regions));
+}
+
+bool rcheevos_memory_init(rcheevos_memory_regions_t* regions, int console)
+{
+   const rc_memory_regions_t* console_regions = rc_console_memory_regions(console);
+   rcheevos_memory_regions_t new_regions;
+   bool has_valid_region = false;
+   unsigned i;
+
+   if (regions == NULL)
+      return false;
+
+   memset(&new_regions, 0, sizeof(new_regions));
+
+   if (console_regions == NULL || console_regions->num_regions == 0)
+   {
+      rcheevos_memory_init_without_regions(&new_regions);
+   }
+   else
+   {
+      rarch_system_info_t* system = runloop_get_system_info();
+      if (system->mmaps.num_descriptors != 0)
+         rcheevos_memory_init_from_memory_map(&new_regions, &system->mmaps, console_regions);
+      else
+         rcheevos_memory_init_from_unmapped_memory(&new_regions, console_regions, console);
+   }
+
+   /* determine if any valid regions were found */
+   for (i = 0; i < new_regions.count; i++)
+   {
+      if (new_regions.data[i] != NULL)
+      {
+         has_valid_region = true;
+         break;
+      }
+   }
+
+   memcpy(regions, &new_regions, sizeof(*regions));
+   return has_valid_region;
+}
diff --git a/cheevos/fixup.h b/cheevos/memory.h
similarity index 62%
rename from cheevos/fixup.h
rename to cheevos/memory.h
index c0021fb6d9..a99fe7b0c9 100644
--- a/cheevos/fixup.h
+++ b/cheevos/memory.h
@@ -12,36 +12,31 @@
  *  You should have received a copy of the GNU General Public License along with RetroArch.
  *  If not, see <http://www.gnu.org/licenses/>.
  */
-
-#ifndef __RARCH_CHEEVOS_FIXUP_H
-#define __RARCH_CHEEVOS_FIXUP_H
+#ifndef __RARCH_CHEEVOS_MEMORY_H
+#define __RARCH_CHEEVOS_MEMORY_H
 
 #include <stdint.h>
+#include <stdlib.h>
 #include <boolean.h>
 
 #include <retro_common_api.h>
 
 RETRO_BEGIN_DECLS
 
-typedef struct
-{
-   unsigned address;
-   const uint8_t* location;
-} rcheevos_fixup_t;
+#define MAX_MEMORY_REGIONS 32
 
 typedef struct
 {
-   rcheevos_fixup_t* elements;
-   unsigned capacity, count;
-   bool dirty;
-} rcheevos_fixups_t;
+   uint8_t* data[MAX_MEMORY_REGIONS];
+   size_t size[MAX_MEMORY_REGIONS];
+   unsigned count;
+   size_t total_size;
+} rcheevos_memory_regions_t;
 
-void rcheevos_fixup_init(rcheevos_fixups_t* fixups);
-void rcheevos_fixup_destroy(rcheevos_fixups_t* fixups);
+bool rcheevos_memory_init(rcheevos_memory_regions_t* regions, int console);
+void rcheevos_memory_destroy(rcheevos_memory_regions_t* regions);
 
-const uint8_t* rcheevos_fixup_find(rcheevos_fixups_t* fixups, unsigned address, int console);
-
-const uint8_t* rcheevos_patch_address(unsigned address, int console);
+uint8_t* rcheevos_memory_find(const rcheevos_memory_regions_t* regions, unsigned address);
 
 RETRO_END_DECLS
 
diff --git a/deps/rcheevos/src/rcheevos/consoleinfo.c b/deps/rcheevos/src/rcheevos/consoleinfo.c
index 063e3a8209..75879f9cbe 100644
--- a/deps/rcheevos/src/rcheevos/consoleinfo.c
+++ b/deps/rcheevos/src/rcheevos/consoleinfo.c
@@ -259,7 +259,7 @@ static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
     { 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (bank 1)" },
     { 0x00E000U, 0x00FDFFU, 0x00C000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Echo RAM" },
     { 0x00FE00U, 0x00FE9FU, 0x00FE00U, RC_MEMORY_TYPE_VIDEO_RAM, "Sprite RAM"},
-    { 0x00FEA0U, 0x00FEFFU, 0x00FEA0U, RC_MEMORY_TYPE_READONLY, "Unusable"},
+    { 0x00FEA0U, 0x00FEFFU, 0x00FEA0U, RC_MEMORY_TYPE_UNUSED, ""},
     { 0x00FF00U, 0x00FF7FU, 0x00FF00U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Hardware I/O"},
     { 0x00FF80U, 0x00FFFEU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "Quick RAM"},
     { 0x00FFFFU, 0x00FFFFU, 0x00FFFFU, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt enable"},
diff --git a/griffin/griffin.c b/griffin/griffin.c
index 9c0bf60a89..18bce931f5 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -195,7 +195,7 @@ ACHIEVEMENTS
 
 #include "../cheevos/cheevos.c"
 #include "../cheevos/badges.c"
-#include "../cheevos/fixup.c"
+#include "../cheevos/memory.c"
 #include "../cheevos/hash.c"
 #include "../cheevos/parser.c"
 
diff --git a/retroarch.c b/retroarch.c
index 6a88c3108e..d89651d22d 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -170,7 +170,6 @@
 
 #ifdef HAVE_CHEEVOS
 #include "cheevos/cheevos.h"
-#include "cheevos/fixup.h"
 #endif
 
 #ifdef HAVE_TRANSLATE
@@ -12767,7 +12766,7 @@ static bool command_read_ram(const char *arg)
    reply_at                = reply + snprintf(
          reply, alloc_size - 1, "READ_CORE_RAM" " %x", addr);
 
-   if ((data = rcheevos_patch_address(addr, rcheevos_get_console())))
+   if ((data = rcheevos_patch_address(addr)))
    {
       for (i = 0; i < nbytes; i++)
          snprintf(reply_at + 3 * i, 4, " %.2X", data[i]);
@@ -12787,12 +12786,17 @@ static bool command_read_ram(const char *arg)
 static bool command_write_ram(const char *arg)
 {
    unsigned int addr    = strtoul(arg, (char**)&arg, 16);
-   uint8_t *data        = (uint8_t *)rcheevos_patch_address(
-         addr, rcheevos_get_console());
+   uint8_t *data        = (uint8_t *)rcheevos_patch_address(addr);
 
    if (!data)
       return false;
 
+   if (rcheevos_hardcore_active && rcheevos_loaded && !rcheevos_hardcore_paused)
+   {
+      RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_RAM\n");
+      rcheevos_pause_hardcore();
+   }
+
    while (*arg)
    {
       *data = strtoul(arg, (char**)&arg, 16);

From 0609d229a6faef3598a81c5ac55b314feaeb2004 Mon Sep 17 00:00:00 2001
From: Jamiras <jamirasmt@gmail.com>
Date: Tue, 11 Aug 2020 10:21:10 -0600
Subject: [PATCH 2/4] address travis warnings

---
 cheevos/memory.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/cheevos/memory.c b/cheevos/memory.c
index 37e73897ab..8886826b89 100644
--- a/cheevos/memory.c
+++ b/cheevos/memory.c
@@ -102,21 +102,21 @@ static void rcheevos_memory_init_without_regions(rcheevos_memory_regions_t* regi
 
    meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
    core_get_memory(&meminfo);
-   rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SYSTEM_RAM, meminfo.data, meminfo.size, description);
+   rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SYSTEM_RAM, (uint8_t*)meminfo.data, meminfo.size, description);
 
    meminfo.id = RETRO_MEMORY_SAVE_RAM;
    core_get_memory(&meminfo);
-   rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, meminfo.data, meminfo.size, description);
+   rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, (uint8_t*)meminfo.data, meminfo.size, description);
 }
 
 static const rarch_memory_descriptor_t* rcheevos_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned real_address)
 {
-   if (mmap->num_descriptors == 0)
-      return NULL;
-
    const rarch_memory_descriptor_t* desc = mmap->descriptors;
    const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
 
+   if (mmap->num_descriptors == 0)
+      return NULL;
+
    for (; desc < end; desc++)
    {
       if (desc->core.select == 0)
@@ -284,13 +284,13 @@ static void rcheevos_memory_init_from_unmapped_memory(rcheevos_memory_regions_t*
       if (console_region_size > meminfo.size)
       {
          /* want more than what is available, take what we can and null fill the rest */
-         rcheevos_memory_register_region(regions, console_region->type, meminfo.data, meminfo.size, description);
+         rcheevos_memory_register_region(regions, console_region->type, (uint8_t*)meminfo.data, meminfo.size, description);
          rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size - meminfo.size, "null filler");
       }
       else
       {
          /* only take as much as we need */
-         rcheevos_memory_register_region(regions, console_region->type, meminfo.data, console_region_size, description);
+         rcheevos_memory_register_region(regions, console_region->type, (uint8_t*)meminfo.data, console_region_size, description);
       }
    }
 }

From 8d34d06c768ca68a43caa06148de45f811c2de49 Mon Sep 17 00:00:00 2001
From: Jamiras <jamirasmt@gmail.com>
Date: Tue, 11 Aug 2020 11:15:00 -0600
Subject: [PATCH 3/4] address LGTM warning

---
 cheevos/memory.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cheevos/memory.c b/cheevos/memory.c
index 8886826b89..7b8cbf2bc0 100644
--- a/cheevos/memory.c
+++ b/cheevos/memory.c
@@ -89,8 +89,8 @@ static void rcheevos_memory_register_region(rcheevos_memory_regions_t* regions,
 
    regions->total_size += size;
 
-   CHEEVOS_LOG(RCHEEVOS_TAG "Registered 0x%04X bytes of %s at $%06X (%s)\n", size,
-      rcheevos_memory_type(type), regions->total_size - size, description);
+   CHEEVOS_LOG(RCHEEVOS_TAG "Registered 0x%04X bytes of %s at $%06X (%s)\n", (unsigned)size,
+      rcheevos_memory_type(type), (unsigned)(regions->total_size - size), description);
 }
 
 static void rcheevos_memory_init_without_regions(rcheevos_memory_regions_t* regions)

From 1f350be1f8e22214f28dfc4f6913b246ab9eab54 Mon Sep 17 00:00:00 2001
From: Jamiras <jamirasmt@gmail.com>
Date: Wed, 12 Aug 2020 08:13:37 -0600
Subject: [PATCH 4/4] rename memory.c and parser.c to be less generic;
 eliminate hash.c

---
 Makefile.common                        |  5 ++---
 cheevos/cheevos.c                      |  5 ++---
 cheevos/{memory.c => cheevos_memory.c} |  2 +-
 cheevos/{memory.h => cheevos_memory.h} |  0
 cheevos/{parser.c => cheevos_parser.c} | 14 ++++++++++--
 cheevos/{parser.h => cheevos_parser.h} |  0
 cheevos/hash.c                         | 12 -----------
 cheevos/hash.h                         | 30 --------------------------
 griffin/griffin.c                      |  5 ++---
 9 files changed, 19 insertions(+), 54 deletions(-)
 rename cheevos/{memory.c => cheevos_memory.c} (99%)
 rename cheevos/{memory.h => cheevos_memory.h} (100%)
 rename cheevos/{parser.c => cheevos_parser.c} (98%)
 rename cheevos/{parser.h => cheevos_parser.h} (100%)
 delete mode 100644 cheevos/hash.c
 delete mode 100644 cheevos/hash.h

diff --git a/Makefile.common b/Makefile.common
index 60e1d844df..7d5f8e43c8 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -1952,9 +1952,8 @@ ifeq ($(HAVE_NETWORKING), 1)
 
       OBJ += cheevos/cheevos.o \
              cheevos/badges.o \
-             cheevos/memory.o \
-             cheevos/parser.o \
-             cheevos/hash.o \
+             cheevos/cheevos_memory.o \
+             cheevos/cheevos_parser.o \
              $(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
              deps/rcheevos/src/rcheevos/alloc.o \
              deps/rcheevos/src/rcheevos/compat.o \
diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c
index 239727f385..a69c28b0cd 100644
--- a/cheevos/cheevos.c
+++ b/cheevos/cheevos.c
@@ -52,9 +52,8 @@
 
 #include "badges.h"
 #include "cheevos.h"
-#include "memory.h"
-#include "parser.h"
-#include "hash.h"
+#include "cheevos_memory.h"
+#include "cheevos_parser.h"
 #include "util.h"
 
 #include "../file_path_special.h"
diff --git a/cheevos/memory.c b/cheevos/cheevos_memory.c
similarity index 99%
rename from cheevos/memory.c
rename to cheevos/cheevos_memory.c
index 7b8cbf2bc0..5d693aa175 100644
--- a/cheevos/memory.c
+++ b/cheevos/cheevos_memory.c
@@ -13,7 +13,7 @@
  *  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "memory.h"
+#include "cheevos_memory.h"
 
 #include "util.h"
 
diff --git a/cheevos/memory.h b/cheevos/cheevos_memory.h
similarity index 100%
rename from cheevos/memory.h
rename to cheevos/cheevos_memory.h
diff --git a/cheevos/parser.c b/cheevos/cheevos_parser.c
similarity index 98%
rename from cheevos/parser.c
rename to cheevos/cheevos_parser.c
index 13cffaa6e9..b8e9c9fa62 100644
--- a/cheevos/parser.c
+++ b/cheevos/cheevos_parser.c
@@ -1,6 +1,5 @@
-#include "parser.h"
+#include "cheevos_parser.h"
 
-#include "hash.h"
 #include "util.h"
 
 #include <encodings/utf.h>
@@ -34,6 +33,17 @@
 Gets a value in a JSON
 *****************************************************************************/
 
+static uint32_t rcheevos_djb2(const char* str, size_t length)
+{
+   const unsigned char* aux = (const unsigned char*)str;
+   uint32_t            hash = 5381;
+
+   while (length--)
+      hash = (hash << 5) + hash + *aux++;
+
+   return hash;
+}
+
 typedef struct
 {
    unsigned    key_hash;
diff --git a/cheevos/parser.h b/cheevos/cheevos_parser.h
similarity index 100%
rename from cheevos/parser.h
rename to cheevos/cheevos_parser.h
diff --git a/cheevos/hash.c b/cheevos/hash.c
deleted file mode 100644
index 07d028a7f4..0000000000
--- a/cheevos/hash.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "hash.h"
-
-uint32_t rcheevos_djb2(const char* str, size_t length)
-{
-   const unsigned char* aux = (const unsigned char*)str;
-   uint32_t            hash = 5381;
-
-   while (length--)
-      hash = ( hash << 5 ) + hash + *aux++;
-
-   return hash;
-}
diff --git a/cheevos/hash.h b/cheevos/hash.h
deleted file mode 100644
index c13b5ecde7..0000000000
--- a/cheevos/hash.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*  RetroArch - A frontend for libretro.
- *  Copyright (C) 2015-2018 - Andre Leiradella
- *
- *  RetroArch is free software: you can redistribute it and/or modify it under the terms
- *  of the GNU General Public License as published by the Free Software Found-
- *  ation, either version 3 of the License, or (at your option) any later version.
- *
- *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- *  PURPOSE.  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along with RetroArch.
- *  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __RARCH_CHEEVOS_HASH_H
-#define __RARCH_CHEEVOS_HASH_H
-
-#include <stdint.h>
-#include <stddef.h>
-
-#include <retro_common_api.h>
-
-RETRO_BEGIN_DECLS
-
-uint32_t rcheevos_djb2(const char* str, size_t length);
-
-RETRO_END_DECLS
-
-#endif
diff --git a/griffin/griffin.c b/griffin/griffin.c
index 18bce931f5..b5b38e2d8a 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -195,9 +195,8 @@ ACHIEVEMENTS
 
 #include "../cheevos/cheevos.c"
 #include "../cheevos/badges.c"
-#include "../cheevos/memory.c"
-#include "../cheevos/hash.c"
-#include "../cheevos/parser.c"
+#include "../cheevos/cheevos_memory.c"
+#include "../cheevos/cheevos_parser.c"
 
 #include "../deps/rcheevos/src/rcheevos/alloc.c"
 #include "../deps/rcheevos/src/rcheevos/compat.c"