diff --git a/HISTORY.txt b/HISTORY.txt
index 518691629..78a938178 100644
--- a/HISTORY.txt
+++ b/HISTORY.txt
@@ -37,7 +37,8 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
 * improved CDD status report accuracy (fixes track looping with Mode 1 patched games using MSU-MD driver)
 * improved Word-RAM byte access accuracy (verified on schematics)
 * improved GFX processing accuracy to halt it while Word RAM is allocated to Main CPU in 2M mode
-* improved GFX timing accuracy (fixes "Night Striker" crashing after completing a game)
+* improved GFX processing timing accuracy (fixes "Night Striker" crashing after completing a game)
+* improved GFX processing robustness in case of word-RAM address overflow (fixes potential emulator crash in Flink level 20)
 * improved Sub-CPU BUSREQ status accuracy
 * disabled 68k and Z80 access to PRG-RAM when SUB-CPU is running (fixes "Dungeon Explorer")
 * disabled CD hardware reset on Soft-Reset (verified on real hardware)
diff --git a/builds/genesis_plus_gx_libretro.dll b/builds/genesis_plus_gx_libretro.dll
index 90e0dd412..32de916e2 100644
Binary files a/builds/genesis_plus_gx_libretro.dll and b/builds/genesis_plus_gx_libretro.dll differ
diff --git a/builds/genplus_cube.dol b/builds/genplus_cube.dol
index 12a21b17a..7e26b0329 100644
Binary files a/builds/genplus_cube.dol and b/builds/genplus_cube.dol differ
diff --git a/builds/genplus_wii.dol b/builds/genplus_wii.dol
index e0940a99e..d4a47526f 100644
Binary files a/builds/genplus_wii.dol and b/builds/genplus_wii.dol differ
diff --git a/core/cart_hw/md_cart.c b/core/cart_hw/md_cart.c
index a5fdb0f29..766289da1 100644
--- a/core/cart_hw/md_cart.c
+++ b/core/cart_hw/md_cart.c
@@ -224,7 +224,8 @@ static const md_entry_t rom_database[] =
   {0x0000,0x19ff,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}},
 /* Soul Blade */
   {0x0000,0x0c5b,0x40,0x40,{{0x63,0x98,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}},
-
+/* Shi San Zhang Ma Jiang: Zhong Guo Mei Nv Pian (only $400004 is checked, other addresses/values are assumed) */
+  {0xffff,0xd41d,0x40,0x40,{{0x63,0x98,0xc9,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}},
 
 /* King of Fighter 98 */
   {0x0000,0xd0a0,0x48,0x4f,{{0x00,0x00,0xaa,0xf0},{0xffffff,0xffffff,0xfc0000,0xfc0000},{0x000000,0x000000,0x480000,0x4c0000},0,0,NULL,m68k_unused_8_w,default_regs_r,NULL}},
diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c
index cc5e65dbf..73ead1a16 100644
--- a/core/cd_hw/cdd.c
+++ b/core/cd_hw/cdd.c
@@ -209,6 +209,9 @@ void cdd_reset(void)
   /* reset status */
   cdd.status = cdd.loaded ? CD_TOC : NO_DISC;
   
+  /* reset pending flag */
+  cdd.pending = 0;
+
   /* reset CD-DA fader (full volume) */
   cdd.fader[0] = cdd.fader[1] = 0x400;
 
@@ -220,6 +223,7 @@ int cdd_context_save(uint8 *state)
 {
   int bufferptr = 0;
   unsigned int offset = 0;
+  uint8 tmp8;
 
   save_param(&cdd.cycles, sizeof(cdd.cycles));
   save_param(&cdd.latency, sizeof(cdd.latency));
@@ -227,7 +231,10 @@ int cdd_context_save(uint8 *state)
   save_param(&cdd.lba, sizeof(cdd.lba));
   save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
   save_param(&cdd.fader, sizeof(cdd.fader));
-  save_param(&cdd.status, sizeof(cdd.status));
+
+  /* 4-bit pending flag and 4-bit CDD status are saved together (to maintain backward savestate compatibility) */
+  tmp8 = cdd.status | (cdd.pending << 4);
+  save_param(&tmp8, sizeof(tmp8));
 
   /* current track is an audio track ? */
   if (cdd.toc.tracks[cdd.index].type == TYPE_AUDIO)
@@ -266,6 +273,7 @@ int cdd_context_load(uint8 *state, char *version)
 {
   unsigned int offset, lba, index;
   int bufferptr = 0;
+  uint8 tmp8;
 
   load_param(&cdd.cycles, sizeof(cdd.cycles));
   load_param(&cdd.latency, sizeof(cdd.latency));
@@ -273,7 +281,11 @@ int cdd_context_load(uint8 *state, char *version)
   load_param(&lba, sizeof(cdd.lba));
   load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
   load_param(&cdd.fader, sizeof(cdd.fader));
-  load_param(&cdd.status, sizeof(cdd.status));
+
+  /* 4-bit pending flag and 4-bit CDD status are saved together (to maintain backward savestate compatibility) */
+  load_param(&tmp8, sizeof(tmp8));
+  cdd.status = tmp8 & 0xf;
+  cdd.pending = tmp8 >> 4;
 
   /* update current sector */
   cdd.lba = lba;
@@ -1869,86 +1881,86 @@ void cdd_update(void)
   {
     /* CDC decoder is still running while disc is not being read (fixes MCD-verificator CDC Flags Test #30) */
     cdc_decoder_update(0);
-  }
-
-  /* scanning disc */
-  if (cdd.status == CD_SCAN)
-  {
-    /* current track index */
-    int index = cdd.index;
-
-    /* fast-forward or fast-rewind */
-    cdd.lba += cdd.scanOffset;
 
-    /* check current track limits */
-    if (cdd.lba >= cdd.toc.tracks[index].end)
+    /* scanning disc */
+    if (cdd.status == CD_SCAN)
     {
-      /* next track */
-      index++;
+      /* current track index */
+      int index = cdd.index;
+
+      /* fast-forward or fast-rewind */
+      cdd.lba += cdd.scanOffset;
 
-      /* check disc limits */
-      if (index < cdd.toc.last)
+      /* check current track limits */
+      if (cdd.lba >= cdd.toc.tracks[index].end)
       {
-        /* skip directly to next track start position */
-        cdd.lba = cdd.toc.tracks[index].start;
+        /* next track */
+        index++;
+
+        /* check disc limits */
+        if (index < cdd.toc.last)
+        {
+          /* skip directly to next track start position */
+          cdd.lba = cdd.toc.tracks[index].start;
+        }
+        else
+        {
+          /* end of disc */
+          cdd.lba = cdd.toc.end;
+          cdd.index = cdd.toc.last;
+          cdd.status = CD_END;
+
+          /* no audio track playing */
+          scd.regs[0x36>>1].byte.h = 0x01;
+          return;
+        }
       }
-      else
+      else if (cdd.lba < cdd.toc.tracks[index].start)
       {
-        /* end of disc */
-        cdd.lba = cdd.toc.end;
-        cdd.index = cdd.toc.last;
-        cdd.status = CD_END;
+        /* check disc limits */
+        if (index > 0)
+        {
+          /* previous track */
+          index--;
 
-        /* no audio track playing */
-        scd.regs[0x36>>1].byte.h = 0x01;
-        return;
+          /* skip directly to previous track end position */
+          cdd.lba = cdd.toc.tracks[index].end;
+        }
+        else
+        {
+          /* start of first track */
+          cdd.lba = 0;
+        }
       }
-    }
-    else if (cdd.lba < cdd.toc.tracks[index].start)
-    {
-      /* check disc limits */
-      if (index > 0)
+
+      /* seek to current subcode position */
+      if (cdd.toc.sub)
       {
-        /* previous track */
-        index--;
+        cdStreamSeek(cdd.toc.sub, cdd.lba * 96, SEEK_SET);
+      }
+
+      /* current track is an audio track ? */
+      if (cdd.toc.tracks[index].type == TYPE_AUDIO)
+      {
+        /* seek to current track sector */
+        cdd_seek_audio(index, cdd.lba);
 
-        /* skip directly to previous track end position */
-        cdd.lba = cdd.toc.tracks[index].end;
+        /* audio track playing */
+        scd.regs[0x36>>1].byte.h = 0x00;
       }
       else
       {
-        /* start of first track */
-        cdd.lba = 0;
+        /* no audio track playing */
+        scd.regs[0x36>>1].byte.h = 0x01;
       }
-    }
-
-    /* seek to current subcode position */
-    if (cdd.toc.sub)
-    {
-      cdStreamSeek(cdd.toc.sub, cdd.lba * 96, SEEK_SET);
-    }
-
-    /* current track is an audio track ? */
-    if (cdd.toc.tracks[index].type == TYPE_AUDIO)
-    {
-      /* seek to current track sector */
-      cdd_seek_audio(index, cdd.lba);
 
-      /* audio track playing */
-      scd.regs[0x36>>1].byte.h = 0x00;
-    }
-    else
-    {
-      /* no audio track playing */
-      scd.regs[0x36>>1].byte.h = 0x01;
+      /* udpate current track index */
+      cdd.index = index;
     }
-
-    /* udpate current track index */
-    cdd.index = index;
   }
 
-  /* seeking should start with at least one interrupt delay (fixes Radical Rex incorrect PRG-RAM & Word-RAM initialization, causing missing sprites during intro) */
-  if (scd.regs[0x38>>1].byte.h == CD_SEEK)
+  /* check if seeking is pending */
+  if (cdd.pending)
   {
     /* reset track index */
     int index = 0;
@@ -2016,8 +2028,11 @@ void cdd_update(void)
     /* no audio track playing (yet) */
     scd.regs[0x36>>1].byte.h = 0x01;
 
-    /* update CDD status to either PLAY or PAUSE depending on host command (will be reported to host once seeking has ended) */
-    cdd.status = scd.regs[0x42>>1].byte.h & 0x05;
+    /* update CDD status with pending end status (will be reported to host once seeking has ended) */
+    cdd.status = cdd.pending;
+
+    /* clear pending flag */
+    cdd.pending = 0;
   }
 }
 
@@ -2202,6 +2217,10 @@ void cdd_process(void)
       scd.regs[0x3c>>1].w = 0x0000;
       scd.regs[0x3e>>1].w = 0x0000;
       scd.regs[0x40>>1].w = ~(CD_SEEK + 0x0f) & 0x0f;
+
+      /* seeking should start with at least one interrupt delay (fixes Radical Rex incorrect PRG-RAM & Word-RAM initialization, causing missing sprites during intro) */
+      /* so pending flag is set (with CDD end status) to indicate seeking is pending */
+      cdd.pending = CD_PLAY;
       return;
     }
 
@@ -2213,6 +2232,10 @@ void cdd_process(void)
       scd.regs[0x3c>>1].w = 0x0000;
       scd.regs[0x3e>>1].w = 0x0000;
       scd.regs[0x40>>1].w = ~(CD_SEEK + 0x0f) & 0x0f;
+
+      /* seeking should start with at least one interrupt delay (same as 'Play' command) */
+      /* so pending flag is set (with CDD end status) to indicate seeking is pending */
+      cdd.pending = CD_PAUSE;
       return;
     }
 
diff --git a/core/cd_hw/cdd.h b/core/cd_hw/cdd.h
index f2f780026..4c2ba5cc8 100644
--- a/core/cd_hw/cdd.h
+++ b/core/cd_hw/cdd.h
@@ -117,6 +117,7 @@ typedef struct
   int scanOffset;
   uint16 fader[2];
   uint8 status;
+  uint8 pending;
   uint16 sectorSize;
   toc_t toc;
 #if defined(USE_LIBCHDR)
diff --git a/core/cd_hw/gfx.c b/core/cd_hw/gfx.c
index 85600e354..9221f508c 100644
--- a/core/cd_hw/gfx.c
+++ b/core/cd_hw/gfx.c
@@ -455,9 +455,11 @@ int gfx_context_load(uint8 *state)
   load_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
 
   load_param(&tmp32, 4);
+  tmp32 &= 0x3fff8;
   gfx.tracePtr = (uint16 *)(scd.word_ram_2M + tmp32);
 
   load_param(&tmp32, 4);
+  tmp32 &= ~((1 << ((2*gfx.mapShift) + 1)) - 1) & 0x3ffff;
   gfx.mapPtr = (uint16 *)(scd.word_ram_2M + tmp32);
 
   return bufferptr;
@@ -480,6 +482,12 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
   uint32 xoffset = (int16) *gfx.tracePtr++;
   uint32 yoffset = (int16) *gfx.tracePtr++;
 
+  /* handle trace vector address overflow */
+  if (gfx.tracePtr == (uint16 *)(scd.word_ram_2M + 0x40000))
+  {
+    gfx.tracePtr = (uint16 *)(scd.word_ram_2M);
+  }
+
   /* process all dots */
   while (width--)
   {
@@ -557,7 +565,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
     }
 
     /* read out paired pixel data */
-    pixel_in = READ_BYTE(scd.word_ram_2M, bufferIndex >> 1);
+    pixel_in = READ_BYTE(scd.word_ram_2M, (bufferIndex >> 1) & 0x3ffff);
 
     /* update left or rigth pixel */
     if (bufferIndex & 1)
@@ -573,7 +581,7 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
     pixel_out = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][pixel_in][pixel_out];
 
     /* write data to image buffer */
-    WRITE_BYTE(scd.word_ram_2M, bufferIndex >> 1, pixel_out);
+    WRITE_BYTE(scd.word_ram_2M, (bufferIndex >> 1) & 0x3ffff, pixel_out);
 
     /* check current pixel position  */
     if ((bufferIndex & 7) != 7)
@@ -657,7 +665,7 @@ void gfx_start(unsigned int base, int cycles)
   /* reference: https://github.com/MiSTer-devel/MegaCD_MiSTer/blob/master/docs/mcd%20logs/graphics_operations_and_68k_wordram_access.jpg */
   /* TODO: figure what happen exactly when pixel offset is different from 0 */
   /*       for the moment, one additional read-modify-write access is assumed at the start if pixel offset is not aligned to 4 pixels */
-  gfx.cyclesPerLine = 4 * 3 * (4 + 2 * scd.regs[0x62>>1].w + ((scd.regs[0x62>>1].w + (scd.regs[0x60>>1].byte.l & 0x03) + 3) >> 2));
+  gfx.cyclesPerLine = 4 * 3 * (4 + 2 * (scd.regs[0x62>>1].w & 0x1ff) + (((scd.regs[0x62>>1].w & 0x1ff) + (scd.regs[0x60>>1].byte.l & 0x03) + 3) >> 2));
 
   /* start graphics operation */
   scd.regs[0x58>>1].byte.h = 0x80;
@@ -731,7 +739,7 @@ void gfx_update(int cycles)
       while (lines--)
       {
         /* process dots to image buffer */
-        gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
+        gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w & 0x1ff);
 
         /* increment image buffer start index for next line (8 pixels/line) */
         gfx.bufferStart += 8;