core vdp, some restructuring (layer/window drawing)
authorkub <derkub@gmail.com>
Thu, 8 Aug 2024 20:33:42 +0000 (22:33 +0200)
committerkub <derkub@gmail.com>
Thu, 8 Aug 2024 22:01:19 +0000 (00:01 +0200)
pico/draw.c

index 6d27f1b..12d0d93 100644 (file)
@@ -85,8 +85,8 @@ u32 VdpSATCache[2*128];  // VDP sprite cache (1st 32 sprite attr bits)
 #define LF_PLANE   (1 << 0) // must be = 1\r
 #define LF_SH      (1 << 1) // must be = 2\r
 //#define LF_FORCE   (1 << 2)\r
-#define LF_LINE    (1 << 3) // covers the line\r
-#define LF_LPRIO   (1 << 8) // seen low prio tile\r
+#define LF_LINE    (1 << 3) // layer covers line\r
+#define LF_LPRIO   (1 << 8) // line has low prio tiles\r
 \r
 #define LF_PLANE_A 0\r
 #define LF_PLANE_B 1\r
@@ -284,7 +284,6 @@ TileFlipMakerAS(TileFlipAS_onlymark, pix_sh_as_onlymark)
 // NB s/h already resolved by non-forced drawing\r
 // forced both layer draw (through debug reg)\r
 #define pix_and(x) \\r
-  pal |= 0xc0; /* leave s/h bits untouched in pixel "and" */ \\r
   pd[x] &= pal|t\r
 \r
 TileNormMaker(TileNorm_and, pix_and)\r
@@ -292,7 +291,6 @@ TileFlipMaker(TileFlip_and, pix_and)
 \r
 // forced sprite draw (through debug reg)\r
 #define pix_sh_as_and(x) \\r
-  pal |= 0xc0; /* leave s/h bits untouched in pixel "and" */ \\r
   if (likely(m & (1<<(x+8)))) { \\r
     m &= ~(1<<(x+8)); \\r
     /* if (!t) pd[x] |= 0x40; as per titan hw notes? */ \\r
@@ -305,33 +303,30 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)
 \r
 // --------------------------------------------\r
 \r
-#ifndef _ASM_DRAW_C\r
-#define DrawTile(mask,masked) {                                                \\r
+#define DrawTile(mask,yshift,ymask,hpcode,cache) {                     \\r
   if (code!=oldcode) {                                                 \\r
     oldcode = code;                                                    \\r
                                                                        \\r
     pack = 0;                                                          \\r
     if (code != blank) {                                               \\r
       /* Get tile address/2: */                                                \\r
-      u32 addr = ((code&0x7ff)<<4) + ty;                               \\r
-      if (code & 0x1000) addr ^= 0xe; /* Y-flip */                     \\r
+      u32 addr = ((code<<yshift)&0x7ff0) + ty;                         \\r
+      if (code & 0x1000) addr ^= ymask<<1; /* Y-flip */                        \\r
                                                                        \\r
       pal = ((code>>9)&0x30) | sh; /* shadow */                                \\r
-                                                                       \\r
       pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));                   \\r
       if (!pack)                                                       \\r
         blank = code;                                                  \\r
     }                                                                  \\r
   }                                                                    \\r
-                                                                       \\r
-  if (code & 0x8000) { /* (un-forced) high priority tile */            \\r
+  if (cache && (code & 0x8000)) { /* (un-forced) high priority tile */ \\r
     if (sh | (pack&mask)) {                                            \\r
-      code |= (dx<<16) | (ty<<26) | (masked<<25);                      \\r
-      if (code & 0x1000) code ^= 0xe<<26;                              \\r
-      *hc++ = code, *hc++ = pack&mask; /* cache it */                  \\r
+      code = hpcode | (dx<<16);                                                \\r
+      if (code & 0x1000) code ^= ymask<<(26+1); /* Y-flip */           \\r
+      *hc++ = code; *hc++ = pack&mask; /* cache it */                  \\r
     }                                                                  \\r
   } else {                                                             \\r
-    lflags |= LF_LPRIO;                                                        \\r
+    if (cache) lflags |= LF_LPRIO;                                     \\r
     if (pack&mask) {                                                   \\r
       if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);            \\r
       else               TileNorm(pd + dx, pack&mask, pal);            \\r
@@ -339,355 +334,261 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)
   }                                                                    \\r
 }\r
 \r
-static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)\r
-{\r
-  unsigned char *pd = Pico.est.HighCol;\r
-  u32 *hc = ts->hc;\r
-  int tilex, dx, ty, cells;\r
-  u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
-  u32 pal = 0, pack = 0, sh, mask;\r
-\r
-  // Draw tiles across screen:\r
-  sh = (lflags & LF_SH) << 6; // shadow\r
-  tilex=((-ts->hscroll)>>3)+cellskip;\r
-  ty=(ts->line&7)<<1; // Y-Offset into tile\r
-  dx=((ts->hscroll-1)&7)+1;\r
-  cells = ts->cells - cellskip;\r
-  dx+=cellskip<<3;\r
-\r
-  if (dx & 7) {\r
-    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    mask = 0xffffffff<<((dx&7)*4);\r
-    if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
-    mask = (~mask << 16) | (~mask >> 16);\r
-\r
-    DrawTile(mask,1);\r
-    dx += 8, tilex++, cells--;\r
-  }\r
-\r
-//  int force = (lflags&LF_FORCE) << 13;\r
-  for (; cells > 0; dx+=8, tilex++, cells--)\r
-  {\r
-    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    if (code != blank || ((code & 0x8000) && sh))\r
-      DrawTile(~0,0);\r
-  }\r
-\r
-  if (dx & 7) {\r
-    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    if (code != blank || ((code & 0x8000) && sh)) {\r
-      mask = 0xffffffff<<((dx&7)*4);\r
-      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
-      mask = (mask << 16) | (mask >> 16);\r
-\r
-      DrawTile(mask,1);\r
-    }\r
-  }\r
-\r
-  // terminate the cache list\r
-  *hc = 0;\r
-\r
-  // flags bit is clear if all layer is hi priority\r
-  if (!(lflags & LF_LPRIO) && (lflags & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
-}\r
-\r
-#define DrawTileVSRam(mask,masked) {                                   \\r
-  if (code!=oldcode) {                                                 \\r
-    oldcode = code;                                                    \\r
-    /* Get tile address/2: */                                          \\r
-    addr = (code&0x7ff)<<4;                                            \\r
+#define DrawStripMaker(funcname,yshift,ymask,hpcode,drawtile,cache)    \\r
+void funcname(struct TileStrip *ts, int lflags, int cellskip)          \\r
+{                                                                      \\r
+  unsigned char *pd = Pico.est.HighCol;                                        \\r
+  u32 *hc = ts->hc;                                                    \\r
+  int tilex, dx, ty, cells;                                            \\r
+  u32 code, oldcode = -1, blank = -1; /* The tile we know is blank */  \\r
+  u32 pal = 0, pack = 0, sh, mask = ~0;                                        \\r
+                                                                       \\r
+  /* Draw tiles across screen: */                                      \\r
+  sh = (lflags & LF_SH) << 6; /* shadow */                             \\r
+  tilex=((-ts->hscroll)>>3)+cellskip;                                  \\r
+  ty=(ts->line&ymask)<<1; /* Y-Offset into tile */                     \\r
+  dx=((ts->hscroll-1)&7)+1;                                            \\r
+  cells = ts->cells - cellskip;                                                \\r
+  dx+=cellskip<<3;                                                     \\r
                                                                        \\r
-    pal = ((code>>9)&0x30) | sh; /* shadow */                          \\r
+/*  int force = (plane_sh&LF_FORCE) << 13; */                          \\r
+  if (dx & 7) {                                                                \\r
+    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];            \\r
+/*    code &= ~force; *//* forced always draw everything */            \\r
                                                                        \\r
-    pack = (code & 0x1000 ? ty^0xe : ty); /* Y-flip */                 \\r
-    pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr+pack));                        \\r
-    if (!pack)                                                         \\r
-      blank = code;                                                    \\r
+    mask = 0xffffffff<<((dx&7)*4);                                     \\r
+    if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);                  \\r
+    mask = (~mask << 16) | (~mask >> 16);                              \\r
+                                                                       \\r
+    drawtile(mask,yshift,ymask,hpcode | (ty<<26) | (1<<25),cache);     \\r
+    dx += 8, tilex++, cells--;                                         \\r
   }                                                                    \\r
                                                                        \\r
-  if (code & 0x8000) { /* (un-forced) high priority tile */            \\r
-    if (sh | (pack&mask)) {                                            \\r
-      code |= (dx<<16) | (masked<<25);                                 \\r
-      if (code & 0x1000) code ^= 0xe<<26;                              \\r
-      *hc++ = code, *hc++ = pack&mask; /* cache it */                  \\r
-    }                                                                  \\r
-  } else {                                                             \\r
-    plane_sh |= LF_LPRIO;                                              \\r
-    if (pack&mask) {                                                   \\r
-      if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);            \\r
-      else               TileNorm(pd + dx, pack&mask, pal);            \\r
+  for (; cells > 0; dx+=8, tilex++, cells--)                           \\r
+  {                                                                    \\r
+    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];            \\r
+/*    code &= ~force; *//* forced always draw everything */            \\r
+                                                                       \\r
+    if (code != blank || ((code & 0x8000) && sh))                      \\r
+      drawtile(~0,yshift,ymask,hpcode | (ty<<26),cache);               \\r
+  }                                                                    \\r
+                                                                       \\r
+  if (dx & 7) {                                                                \\r
+    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];            \\r
+/*    code &= ~force; *//* forced always draw everything */            \\r
+                                                                       \\r
+    if (code != blank || ((code & 0x8000) && sh)) {                    \\r
+      mask = 0xffffffff<<((dx&7)*4);                                   \\r
+      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);                        \\r
+      mask = (mask << 16) | (mask >> 16);                              \\r
+                                                                       \\r
+      drawtile(mask,yshift,ymask,hpcode | (ty<<26) | (1<<25),cache);   \\r
     }                                                                  \\r
   }                                                                    \\r
+                                                                       \\r
+  /* terminate the cache list */                                       \\r
+  if (cache) *hc = 0;                                                  \\r
+                                                                       \\r
+  /* if oldcode wasn't changed, it means all layer is hi priority */   \\r
+  if (cache && (lflags & (LF_LINE|LF_LPRIO)) == LF_LINE) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; \\r
 }\r
 \r
-// this is messy\r
-static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)\r
-{\r
-  unsigned char *pd = Pico.est.HighCol;\r
-  u32 *hc = ts->hc;\r
-  int tilex, dx, ty = 0, addr = 0, cell = 0, nametabadd = 0;\r
-  u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
-  u32 pal = 0, pack, scan = Pico.est.DrawScanline, sh, plane, mask;\r
-\r
-  // Draw tiles across screen:\r
-  sh = (plane_sh & LF_SH) << 6; // shadow\r
-  plane = (plane_sh & LF_PLANE); // plane to draw\r
-  tilex=(-ts->hscroll)>>3;\r
-  dx=((ts->hscroll-1)&7)+1;\r
-  if (ts->hscroll & 0x0f) {\r
-    int adj = ((ts->hscroll ^ dx) >> 3) & 1;\r
-    cell -= adj + 1;\r
-    ts->cells -= adj;\r
-    PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = plane_sh >> 16;\r
-  }\r
-  cell+=cellskip;\r
-  tilex+=cellskip;\r
-  dx+=cellskip<<3;\r
-\r
-//  int force = (plane_sh&LF_FORCE) << 13;\r
-  if ((cell&1)==1 || (dx&7)) {\r
-    int line,vscroll;\r
-    vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
-\r
-    // Find the line in the name table\r
-    line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
-    nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
-    ty=(line&7)<<1; // Y-Offset into tile\r
-  }\r
-  if (dx & 7) {\r
-    code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)];\r
-    code |= ty<<26; // add ty since that can change pixel row for every 2nd tile\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    mask = 0xffffffff<<((dx&7)*4);\r
-    if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
-    mask = (~mask << 16) | (~mask >> 16);\r
-\r
-    DrawTileVSRam(mask,1);\r
-\r
-    dx += 8, tilex++, cell++;\r
-  }\r
-  for (; cell < ts->cells; dx+=8,tilex++,cell++)\r
-  {\r
-    if ((cell&1)==0) {\r
-      int line,vscroll;\r
-      vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
-\r
-      // Find the line in the name table\r
-      line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
-      nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
-      ty=(line&7)<<1; // Y-Offset into tile\r
-    }\r
-\r
-    code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)];\r
-    code |= ty<<26; // add ty since that can change pixel row for every 2nd tile\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    if (code != blank || ((code & 0x8000) && sh))\r
-      DrawTileVSRam(~0,0);\r
-  }\r
-  if (dx & 7) {\r
-    if ((cell&1)==0) {\r
-      int line,vscroll;\r
-      vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
-\r
-      // Find the line in the name table\r
-      line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
-      nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
-      ty=(line&7)<<1; // Y-Offset into tile\r
-    }\r
-\r
-    code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)];\r
-    code |= ty<<26; // add ty since that can change pixel row for every 2nd tile\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    if (code != blank || ((code & 0x8000) && sh)) {\r
-      mask = 0xffffffff<<((dx&7)*4);\r
-      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
-      mask = (mask << 16) | (mask >> 16);\r
-\r
-      DrawTileVSRam(mask,1);\r
-    }\r
-  }\r
-\r
-  // terminate the cache list\r
-  *hc = 0;\r
+#ifndef _ASM_DRAW_C\r
+static DrawStripMaker(DrawStrip, 4, 0x7, code, DrawTile, 1);\r
 \r
-  if (!(plane_sh & LF_LPRIO) && (plane_sh & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
-}\r
+static\r
 #endif\r
+       DrawStripMaker(DrawStripInterlace, 5, 0xf, (code&0xfc00) | ((code&0x3ff)<<1), DrawTile, 1);\r
 \r
-#define DrawTileInterlace(mask,masked) {                               \\r
-  if (code!=oldcode) {                                                 \\r
-    oldcode = code;                                                    \\r
+// this is messy\r
+#define DrawStripVSRamMaker(funcname,yshift,ymask,hpcode,drawtile,cache) \\r
+void funcname(struct TileStrip *ts, int lflags, int cellskip)          \\r
+{                                                                      \\r
+  unsigned char *pd = Pico.est.HighCol;                                        \\r
+  u32 *hc = ts->hc;                                                    \\r
+  int tilex, dx, ty = 0, cell = 0, nametabadd = 0;                     \\r
+  u32 code, oldcode = -1, blank = -1; /* The tile we know is blank */  \\r
+  u32 pal = 0, pack = 0, sh, plane, mask;                              \\r
+  int scan = Pico.est.DrawScanline<<(yshift-4);                                \\r
                                                                        \\r
-    pack = 0;                                                          \\r
-    if (code != blank) {                                               \\r
-      /* Get tile address/2: */                                                \\r
-      u32 addr = ((code&0x3ff)<<5) + ty;                               \\r
-      if (code & 0x1000) addr ^= 0x1e; /* Y-flip */                    \\r
+  /* Draw tiles across screen: */                                      \\r
+  sh = (lflags & LF_SH) << 6; /* shadow */                             \\r
+  plane = (lflags & LF_PLANE); /* plane to draw */                     \\r
+  tilex=(-ts->hscroll)>>3;                                             \\r
+  dx=((ts->hscroll-1)&7)+1;                                            \\r
+  if (ts->hscroll & 0x0f) {                                            \\r
+    int adj = ((ts->hscroll ^ dx) >> 3) & 1;                           \\r
+    cell -= adj + 1;                                                   \\r
+    ts->cells -= adj;                                                  \\r
+    PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = lflags >> 16;          \\r
+  }                                                                    \\r
+  cell+=cellskip;                                                      \\r
+  tilex+=cellskip;                                                     \\r
+  dx+=cellskip<<3;                                                     \\r
                                                                        \\r
-      pal = ((code>>9)&0x30) | sh; /* shadow */                                \\r
+/*  int force = (lflags&LF_FORCE) << 13; */                            \\r
+  if ((cell&1)==1 || (dx&7)) {                                         \\r
+    int line,vscroll;                                                  \\r
+    vscroll = PicoMem.vsram[plane + (cell&0x3e)];                      \\r
                                                                        \\r
-      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));                   \\r
-      if (!pack)                                                       \\r
-        blank = code;                                                  \\r
+    /* Find the line in the name table */                              \\r
+    line=(vscroll+scan)&(u16)ts->line;    /* ts->line is really ymask, */ \\r
+    nametabadd=(line>>(yshift-1))<<(ts->line>>24); /* and shift[width] */ \\r
+    ty=((line<<(yshift-4))&ymask)<<1; /* Y-Offset into tile */         \\r
+  }                                                                    \\r
+  if (dx & 7) {                                                                \\r
+    code = PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; \\r
+    code |= ty<<26; /* add ty since that can change pixel row for every 2nd tile */ \\r
+/*    code &= ~force; *//* forced always draw everything */            \\r
+                                                                       \\r
+    mask = 0xffffffff<<((dx&7)*4);                                     \\r
+    if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);                  \\r
+    mask = (~mask << 16) | (~mask >> 16);                              \\r
+                                                                       \\r
+    drawtile(mask,yshift,ymask,hpcode | (1<<25),cache);                        \\r
+                                                                       \\r
+    dx += 8, tilex++, cell++;                                          \\r
+  }                                                                    \\r
+  for (; cell < ts->cells; dx+=8,tilex++,cell++)                       \\r
+  {                                                                    \\r
+    if ((cell&1)==0)                                                   \\r
+    {                                                                  \\r
+      int line,vscroll;                                                        \\r
+      vscroll = PicoMem.vsram[plane + (cell&0x3e)];                    \\r
+                                                                       \\r
+      /* Find the line in the name table */                            \\r
+      line=(vscroll+scan)&(u16)ts->line;    /* ts->line is really ymask, */ \\r
+      nametabadd=(line>>(yshift-1))<<(ts->line>>24); /* and shift[width] */ \\r
+      ty=((line<<(yshift-4))&ymask)<<1; /* Y-Offset into tile */       \\r
     }                                                                  \\r
+                                                                       \\r
+    code = PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; \\r
+    code |= ty<<26; /* add ty since that can change pixel row for every 2nd tile */ \\r
+/*    code &= ~force; *//* forced always draw everything */            \\r
+                                                                       \\r
+    if (code != blank || ((code & 0x8000) && sh))                      \\r
+      drawtile(~0,yshift,ymask,hpcode,cache);                          \\r
   }                                                                    \\r
+  if (dx & 7) {                                                                \\r
+    if ((cell&1)==0)                                                   \\r
+    {                                                                  \\r
+      int line,vscroll;                                                        \\r
+      vscroll = PicoMem.vsram[plane + (cell&0x3e)];                    \\r
                                                                        \\r
-  if (code & 0x8000) { /* high priority tile */                                \\r
-    if (sh | (pack&mask)) {                                            \\r
-      code = (code&0xfc00) | ((code&0x3ff)<<1) | (dx<<16) | (ty<<26) | (masked<<25);   \\r
-      if (code & 0x1000) code ^= 0x1e<<26;                             \\r
-      *hc++ = code, *hc++ = pack&mask; /* cache it */                  \\r
+      /* Find the line in the name table */                            \\r
+      line=(vscroll+scan)&(u16)ts->line;    /* ts->line is really ymask, */ \\r
+      nametabadd=(line>>(yshift-1))<<(ts->line>>24); /* and shift[width] */ \\r
+      ty=((line<<(yshift-4))&ymask)<<1; /* Y-Offset into tile */       \\r
     }                                                                  \\r
-  } else {                                                             \\r
-    plane_sh |= LF_LPRIO;                                              \\r
-    if (pack&mask) {                                                   \\r
-      if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);            \\r
-      else               TileNorm(pd + dx, pack&mask, pal);            \\r
+                                                                       \\r
+    code = PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; \\r
+    code |= ty<<26; /* add ty since that can change pixel row for every 2nd tile */ \\r
+/*    code &= ~force; *//* forced always draw everything */            \\r
+                                                                       \\r
+    if (code != blank || ((code & 0x8000) && sh)) {                    \\r
+      mask = 0xffffffff<<((dx&7)*4);                                   \\r
+      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);                        \\r
+      mask = (mask << 16) | (mask >> 16);                              \\r
+                                                                       \\r
+      drawtile(mask,yshift,ymask,hpcode | (1<<25),cache);              \\r
     }                                                                  \\r
   }                                                                    \\r
+                                                                       \\r
+  /* terminate the cache list */                                       \\r
+  if (cache) *hc = 0;                                                  \\r
+                                                                       \\r
+  if (cache && (lflags & (LF_LINE|LF_LPRIO)) == LF_LINE) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; \\r
 }\r
 \r
 #ifndef _ASM_DRAW_C\r
+static DrawStripVSRamMaker(DrawStripVSRam, 4, 0x7, code, DrawTile, 1);\r
+\r
 static\r
 #endif\r
-void DrawStripInterlace(struct TileStrip *ts, int plane_sh)\r
-{\r
-  unsigned char *pd = Pico.est.HighCol;\r
-  u32 *hc = ts->hc;\r
-  int tilex = 0, dx = 0, ty = 0, cells;\r
-  u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
-  u32 pal = 0, pack = 0, sh, mask;\r
-\r
-  // Draw tiles across screen:\r
-  sh = (plane_sh & LF_SH) << 6; // shadow\r
-  tilex=(-ts->hscroll)>>3;\r
-  ty=(ts->line&15)<<1; // Y-Offset into tile\r
-  dx=((ts->hscroll-1)&7)+1;\r
-  cells = ts->cells;\r
-\r
-  if (dx & 7) {\r
-    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    mask = 0xffffffff<<(dx*4);\r
-    if (code & 0x0800) mask = 0xffffffff>>(dx*4);\r
-    mask = (~mask << 16) | (~mask >> 16);\r
-\r
-    DrawTileInterlace(mask,1);\r
-    dx += 8, tilex++, cells--;\r
-  }\r
-\r
-//  int force = (plane_sh&LF_FORCE) << 13;\r
-  for (; cells; dx+=8,tilex++,cells--)\r
-  {\r
-    u32 code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    if (code != blank || ((code & 0x8000) && sh))\r
-      DrawTileInterlace(~0,0);\r
-  }\r
-\r
-  if (dx & 7) {\r
-    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-//    code &= ~force; // forced always draw everything\r
-\r
-    if (code != blank || ((code & 0x8000) && sh)) {\r
-      mask = 0xffffffff<<((dx&7)*4);\r
-      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
-      mask = (mask << 16) | (mask >> 16);\r
-\r
-      DrawTileInterlace(mask,1);\r
-    }\r
-  }\r
-\r
-  // terminate the cache list\r
-  *hc = 0;\r
-\r
-  if (!(plane_sh & LF_LPRIO) && (plane_sh & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
-}\r
+       DrawStripVSRamMaker(DrawStripVSRamInterlace, 5, 0xf, (code&0xfc00) | ((code&0x3ff)<<1), DrawTile, 1);\r
 \r
 // --------------------------------------------\r
 \r
-#ifndef _ASM_DRAW_C\r
-static void DrawLayer(int plane_sh, u32 *hcache, int cellskip, int maxcells,\r
-  struct PicoEState *est)\r
-{\r
-  struct PicoVideo *pvid=&est->Pico->video;\r
-  const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid)\r
-  struct TileStrip ts;\r
-  int width, height, ymask;\r
-  int vscroll, htab;\r
-\r
-  ts.hc=hcache;\r
-  ts.cells=maxcells;\r
-\r
-  // Work out the TileStrip to draw\r
-\r
-  // Work out the name table size: 32 64 or 128 tiles (0-3)\r
-  width=pvid->reg[16];\r
-  height=(width>>4)&3; width&=3;\r
-\r
-  ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f)\r
-  ymask=(height<<8)|0xff;       // Y Mask in pixels\r
-  switch (width) {\r
-    case 1: ymask &= 0x1ff; break;\r
-    case 2: ymask =  0x007; break;\r
-    case 3: ymask =  0x0ff; break;\r
-  }\r
-\r
-  // Find name table:\r
-  if (plane_sh&LF_PLANE) ts.nametab=(pvid->reg[4]&0x07)<<12; // B\r
-  else                   ts.nametab=(pvid->reg[2]&0x38)<< 9; // A\r
-\r
-  htab=pvid->reg[13]<<9; // Horizontal scroll table address\r
-  switch (pvid->reg[11]&3) {\r
-    case 1: htab += (est->DrawScanline<<1) &  0x0f; break;\r
-    case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; // Offset by tile\r
-    case 3: htab += (est->DrawScanline<<1);         break; // Offset by line\r
-  }\r
-  htab+=plane_sh&LF_PLANE; // A or B\r
-\r
-  // Get horizontal scroll value, will be masked later\r
-  ts.hscroll = PicoMem.vram[htab & 0x7fff];\r
-\r
-  if((pvid->reg[12]&6) == 6) {\r
-    // interlace mode 2\r
-    vscroll = PicoMem.vsram[plane_sh&LF_PLANE]; // Get vertical scroll value\r
-\r
-    // Find the line in the name table\r
-    ts.line=(vscroll+(est->DrawScanline<<1))&((ymask<<1)|1);\r
-    ts.nametab+=(ts.line>>4)<<shift[width];\r
-\r
-    DrawStripInterlace(&ts, plane_sh);\r
-  } else if (pvid->reg[11]&4) {\r
-    // shit, we have 2-cell column based vscroll\r
-    // luckily this doesn't happen too often\r
-    ts.line=ymask|(shift[width]<<24); // save some stuff instead of line\r
-    // vscroll value for leftmost cells in case of hscroll not on 16px boundary\r
-    // XXX it's unclear what exactly the hw is doing. Continue reading where it\r
-    // stopped last seems to work best (H40: 0x50 (wrap->0x00), H32 0x40).\r
-    plane_sh |= PicoMem.vsram[(pvid->reg[12]&1?0x00:0x20) + (plane_sh&LF_PLANE)] << 16;\r
-    DrawStripVSRam(&ts, plane_sh, cellskip);\r
-  } else {\r
-    vscroll = PicoMem.vsram[plane_sh&LF_PLANE]; // Get vertical scroll value\r
-\r
-    // Find the line in the name table\r
-    ts.line=(vscroll+est->DrawScanline)&ymask;\r
-    ts.nametab+=(ts.line>>3)<<shift[width];\r
-\r
-    DrawStrip(&ts, plane_sh, cellskip);\r
-  }\r
+#define DrawLayerMaker(funcname,drawstrip,drawstripinterlace,drawstripvsram,drawstripvsraminterlace) \\r
+void funcname(int plane_sh, u32 *hcache, int cellskip, int maxcells, struct PicoEState *est) \\r
+{                                                                      \\r
+  struct PicoVideo *pvid=&est->Pico->video;                            \\r
+  const char shift[4]={5,6,5,7}; /* 32,64 or 128 sized tilemaps (2 is invalid) */ \\r
+  struct TileStrip ts;                                                 \\r
+  int width, height, ymask;                                            \\r
+  int vscroll, htab;                                                   \\r
+                                                                       \\r
+  ts.hc=hcache;                                                                \\r
+  ts.cells=maxcells;                                                   \\r
+                                                                       \\r
+  /* Work out the TileStrip to draw */                                 \\r
+                                                                       \\r
+  /* Work out the name table size: 32 64 or 128 tiles (0-3) */         \\r
+  width=pvid->reg[16];                                                 \\r
+  height=(width>>4)&3; width&=3;                                       \\r
+                                                                       \\r
+  ts.xmask=(1<<shift[width])-1; /* X Mask in tiles (0x1f-0x7f) */      \\r
+  ymask=(height<<8)|0xff;       /* Y Mask in pixels */                 \\r
+  switch (width) {                                                     \\r
+    case 1: ymask &= 0x1ff; break;                                     \\r
+    case 2: ymask =  0x007; break;                                     \\r
+    case 3: ymask =  0x0ff; break;                                     \\r
+  }                                                                    \\r
+                                                                       \\r
+  /* Find name table: */                                               \\r
+  if (plane_sh&LF_PLANE) ts.nametab=(pvid->reg[4]&0x07)<<12; /* B */   \\r
+  else                   ts.nametab=(pvid->reg[2]&0x38)<< 9; /* A */   \\r
+                                                                       \\r
+  htab=pvid->reg[13]<<9; /* Horizontal scroll table address */         \\r
+  switch (pvid->reg[11]&3) {                                           \\r
+    case 1: htab += (est->DrawScanline<<1) &  0x0f; break;             \\r
+    case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; /* Offset by tile */ \\r
+    case 3: htab += (est->DrawScanline<<1);         break; /* Offset by line */ \\r
+  }                                                                    \\r
+  htab+=plane_sh&LF_PLANE; /* A or B */                                        \\r
+                                                                       \\r
+  /* Get horizontal scroll value, will be masked later */              \\r
+  ts.hscroll = PicoMem.vram[htab & 0x7fff];                            \\r
+                                                                       \\r
+  if (likely(!(pvid->reg[11]&4))) {                                    \\r
+    vscroll = PicoMem.vsram[plane_sh&LF_PLANE]; /* Get vertical scroll value */ \\r
+                                                                       \\r
+    if(likely((pvid->reg[12]&6) != 6)) {                               \\r
+      /* Find the line in the name table */                            \\r
+      ts.line=(vscroll+est->DrawScanline)&ymask;                       \\r
+      ts.nametab+=(ts.line>>3)<<shift[width];                          \\r
+                                                                       \\r
+      drawstrip(&ts, plane_sh, cellskip);                              \\r
+    } else {                                                           \\r
+      /* interlace mode 2 */                                           \\r
+                                                                       \\r
+      /* Find the line in the name table */                            \\r
+      ts.line=(vscroll+(est->DrawScanline<<1))&((ymask<<1)|1);         \\r
+      ts.nametab+=(ts.line>>4)<<shift[width];                          \\r
+                                                                       \\r
+      drawstripinterlace(&ts, plane_sh, cellskip);                     \\r
+    }                                                                  \\r
+  } else {                                                             \\r
+    /* shit, we have 2-cell column based vscroll */                    \\r
+    /* luckily this doesn't happen too often */                                \\r
+                                                                       \\r
+    /* vscroll value for leftmost cells in case of hscroll not on 16px boundary */ \\r
+    /* NB it's unclear what exactly the hw is doing. Continue reading where it */ \\r
+    /* stopped last seems to work best (H40: 0x50 (wrap->0x00), H32 0x40). */ \\r
+    plane_sh |= PicoMem.vsram[(pvid->reg[12]&1?0x00:0x20) + (plane_sh&LF_PLANE)] << 16; \\r
+                                                                       \\r
+    if (likely((pvid->reg[12]&6) != 6)) {                              \\r
+      ts.line=ymask|(shift[width]<<24); /* save some stuff instead of line */ \\r
+      drawstripvsram(&ts, plane_sh, cellskip);                         \\r
+    } else {                                                           \\r
+      ts.line=(ymask<<1)|1|(shift[width]<<24); /* save some stuff instead of line */ \\r
+      drawstripvsraminterlace(&ts, plane_sh, cellskip);                        \\r
+    }                                                                  \\r
+  }                                                                    \\r
 }\r
 \r
+#ifndef _ASM_DRAW_C\r
+static DrawLayerMaker(DrawLayer,DrawStrip,DrawStripInterlace,DrawStripVSRam,DrawStripVSRamInterlace);\r
 \r
 // --------------------------------------------\r
 \r
@@ -697,39 +598,42 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
 {\r
   unsigned char *pd = est->HighCol;\r
   struct PicoVideo *pvid = &est->Pico->video;\r
-  int tilex,ty,nametab,code=0;\r
-  int blank=-1; // The tile we know is blank\r
+  int tilex,ty,nametab,code,oldcode=-1,blank=-1; // The tile we know is blank\r
+  int yshift,ymask;\r
+  u32 pack;\r
+  u32 *hc=NULL, lflags=0; // referenced in DrawTile\r
+\r
+  yshift = 4, ymask = 0x7;\r
+  if(likely((pvid->reg[12]&6) == 6))\r
+    yshift = 5, ymask = 0xf;\r
+  ty=((est->DrawScanline<<(yshift-4))&ymask)<<1; // Y-Offset into tile\r
 \r
   // Find name table line:\r
   if (pvid->reg[12]&1)\r
   {\r
     nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode\r
-    nametab+=(est->DrawScanline>>3)<<6;\r
+    nametab+=(est->DrawScanline>>(yshift-1))<<6;\r
   }\r
   else\r
   {\r
     nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode\r
-    nametab+=(est->DrawScanline>>3)<<5;\r
+    nametab+=(est->DrawScanline>>(yshift-1))<<5;\r
   }\r
 \r
-  tilex=tstart<<1;\r
-\r
   if (prio && !(est->rendstatus & PDRAW_WND_DIFF_PRIO)) {\r
     // all tiles processed in low prio pass\r
     return;\r
   }\r
 \r
+  tilex=tstart<<1;\r
   tend<<=1;\r
-  ty=(est->DrawScanline&7)<<1; // Y-Offset into tile\r
 \r
   // Draw tiles across screen:\r
   if (!sh)\r
   {\r
     for (; tilex < tend; tilex++)\r
     {\r
-      unsigned int pack;\r
-      int dx, addr;\r
-      int pal;\r
+      int dx, pal;\r
 \r
       code = PicoMem.vram[nametab + tilex];\r
       if ((code>>15) != prio) {\r
@@ -738,30 +642,16 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
       }\r
       if (code==blank) continue;\r
 \r
-      // Get tile address/2:\r
-      addr=(code&0x7ff)<<4;\r
-      if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip\r
-\r
-      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));\r
-      if (!pack) {\r
-        blank = code;\r
-        continue;\r
-      }\r
-\r
-      pal = ((code >> 9) & 0x30);\r
       dx = 8 + (tilex << 3);\r
 \r
-      if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
-      else               TileNorm(pd + dx, pack, pal);\r
+      DrawTile(~0,yshift,ymask,code,0);\r
     }\r
   }\r
   else\r
   {\r
     for (; tilex < tend; tilex++)\r
     {\r
-      unsigned int pack;\r
-      int dx, addr;\r
-      int pal;\r
+      int dx, pal;\r
 \r
       code = PicoMem.vram[nametab + tilex];\r
       if((code>>15) != prio) {\r
@@ -779,21 +669,9 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
         pal |= 0x80;\r
       }\r
       if(code==blank) continue;\r
-\r
-      // Get tile address/2:\r
-      addr=(code&0x7ff)<<4;\r
-      if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip\r
-\r
-      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));\r
-      if (!pack) {\r
-        blank = code;\r
-        continue;\r
-      }\r
-\r
       dx = 8 + (tilex << 3);\r
 \r
-      if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
-      else               TileNorm(pd + dx, pack, pal);\r
+      DrawTile(~0,yshift,ymask,code,0);\r
     }\r
   }\r
 }\r
@@ -803,10 +681,8 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
 static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est)\r
 {\r
   unsigned char *pd = est->HighCol;\r
-  u32 code, dx;\r
-  u32 pack;\r
-  int pal;\r
-  int hs;\r
+  u32 code, dx, pack;\r
+  int pal, hs;\r
 \r
   // *ts->hc++ = code | (dx<<16) | (ty<<26); // cache it\r
 \r
@@ -817,7 +693,7 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
       // we can process whole line and then act as if sh/hi mode was off,\r
       // but leave lo pri op sprite markers alone\r
       int *zb = (int *)(Pico.est.HighCol+8);\r
-      int c = 320/4;\r
+      int c = 320 / 4;\r
       while (c--)\r
       {\r
         *zb++ &= 0x7f7f7f7f;\r
@@ -830,11 +706,8 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
   if (!sh)\r
   {\r
     while ((code=*hc++)) {\r
-      dx = (code >> 16) & 0x1ff;\r
       pack = *hc++;\r
-      if (!pack)\r
-        continue;\r
-\r
+      dx = (code >> 16) & 0x1ff;\r
       pal = ((code >> 9) & 0x30);\r
 \r
       if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
@@ -846,28 +719,34 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
     while ((code=*hc++)) {\r
       unsigned char *zb;\r
 \r
-      dx = (code >> 16) & 0x1ff;\r
       pack = *hc++;\r
+      dx = (code >> 16) & 0x1ff;\r
+      pal = ((code >> 9) & 0x30);\r
 \r
       zb = est->HighCol+dx;\r
-      if (likely(~code&(1<<25))) {\r
+      if (likely(~code & (1<<25))) {\r
         *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
         *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
       } else {\r
         hs = dx & 7;\r
         if (*hc == 0) // last tile?\r
-          for (            pal = hs; pal < 8;  pal++) *zb++ &= 0x7f;\r
-        else // first tile\r
-          for (zb += 8-hs, pal = 0;  pal < hs; pal++) *zb++ &= 0x7f;\r
+          switch (8-hs) { case 7: *zb++ &= 0x7f;\r
+            case 6: *zb++ &= 0x7f; case 5: *zb++ &= 0x7f; case 4: *zb++ &= 0x7f;\r
+            case 3: *zb++ &= 0x7f; case 2: *zb++ &= 0x7f; case 1: *zb++ &= 0x7f;\r
+          }\r
+        else { // first tile\r
+          zb += 8-hs;\r
+          switch (hs) { case 7: *zb++ &= 0x7f;\r
+            case 6: *zb++ &= 0x7f; case 5: *zb++ &= 0x7f; case 4: *zb++ &= 0x7f;\r
+            case 3: *zb++ &= 0x7f; case 2: *zb++ &= 0x7f; case 1: *zb++ &= 0x7f;\r
+          }\r
+        }\r
       }\r
 \r
-      if (!pack)\r
-        continue;\r
-\r
-      pal = ((code >> 9) & 0x30);\r
-\r
-      if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
-      else               TileNorm(pd + dx, pack, pal);\r
+      if (pack) {\r
+        if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
+        else               TileNorm(pd + dx, pack, pal);\r
+      }\r
     }\r
   }\r
 }\r
@@ -1180,211 +1059,33 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh)
 #ifdef FORCE\r
 // NB lots of duplicate code, all for the sake of a small performance gain.\r
 \r
-static void DrawStripForced(struct TileStrip *ts, int cellskip)\r
-{\r
-  unsigned char *pd = Pico.est.HighCol;\r
-  int tilex, dx, ty, addr=0, cells;\r
-  u32 code = 0, oldcode = -1;\r
-  int pal = 0;\r
-\r
-  // Draw tiles across screen:\r
-  tilex=((-ts->hscroll)>>3)+cellskip;\r
-  ty=(ts->line&7)<<1; // Y-Offset into tile\r
-  dx=((ts->hscroll-1)&7)+1;\r
-  cells = ts->cells - cellskip;\r
-  if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
-  dx+=cellskip<<3;\r
-\r
-  for (; cells > 0; dx+=8, tilex++, cells--)\r
-  {\r
-    u32 pack;\r
-\r
-    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-\r
-    if (code!=oldcode) {\r
-      oldcode = code;\r
-      // Get tile address/2:\r
-      addr = ((code&0x7ff)<<4) + ty;\r
-      if (code & 0x1000) addr^=0xe; // Y-flip\r
-\r
-      pal = (code>>9)&0x30;\r
-    }\r
-\r
-    pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));\r
-\r
-    if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);\r
-    else               TileNorm_and(pd + dx, pack, pal);\r
-  }\r
-}\r
-\r
-static void DrawStripVSRamForced(struct TileStrip *ts, int plane_sh, int cellskip)\r
-{\r
-  unsigned char *pd = Pico.est.HighCol;\r
-  int tilex, dx, ty=0, addr=0, cell=0, nametabadd=0;\r
-  u32 code=0, oldcode=-1;\r
-  int pal=0, scan=Pico.est.DrawScanline, plane;\r
-\r
-  // Draw tiles across screen:\r
-  plane = plane_sh & LF_PLANE;\r
-  tilex=(-ts->hscroll)>>3;\r
-  dx=((ts->hscroll-1)&7)+1;\r
-  if (ts->hscroll & 0x0f) {\r
-    int adj = ((ts->hscroll ^ dx) >> 3) & 1;\r
-    cell -= adj + 1;\r
-    ts->cells -= adj;\r
-    PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = plane_sh >> 16;\r
-  }\r
-  cell+=cellskip;\r
-  tilex+=cellskip;\r
-  dx+=cellskip<<3;\r
-\r
-  if ((cell&1)==1)\r
-  {\r
-    int line,vscroll;\r
-    vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
-\r
-    // Find the line in the name table\r
-    line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
-    nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
-    ty=(line&7)<<1; // Y-Offset into tile\r
-  }\r
-  for (; cell < ts->cells; dx+=8,tilex++,cell++)\r
-  {\r
-    unsigned int pack;\r
-\r
-    if ((cell&1)==0)\r
-    {\r
-      int line,vscroll;\r
-      vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
-\r
-      // Find the line in the name table\r
-      line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
-      nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
-      ty=(line&7)<<1; // Y-Offset into tile\r
-    }\r
-\r
-    code=PicoMem.vram[ts->nametab+nametabadd+(tilex&ts->xmask)];\r
-\r
-    if (code!=oldcode) {\r
-      oldcode = code;\r
-      // Get tile address/2:\r
-      addr=(code&0x7ff)<<4;\r
-\r
-      pal = (code>>9)&0x30; // shadow\r
-    }\r
-\r
-    pack = code & 0x1000 ? ty^0xe : ty; // Y-flip\r
-    pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr+pack));\r
-\r
-    if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);\r
-    else               TileNorm_and(pd + dx, pack, pal);\r
-  }\r
-}\r
-\r
-void DrawStripInterlaceForced(struct TileStrip *ts)\r
-{\r
-  unsigned char *pd = Pico.est.HighCol;\r
-  int tilex = 0, dx = 0, ty = 0, cells;\r
-  int oldcode = -1;\r
-  unsigned int pal = 0, pack = 0;\r
-\r
-  // Draw tiles across screen:\r
-  tilex=(-ts->hscroll)>>3;\r
-  ty=(ts->line&15)<<1; // Y-Offset into tile\r
-  dx=((ts->hscroll-1)&7)+1;\r
-  cells = ts->cells;\r
-  if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
-\r
-  for (; cells; dx+=8,tilex++,cells--)\r
-  {\r
-    u32 code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
-\r
-    if (code!=oldcode) {\r
-      oldcode = code;\r
-\r
-      // Get tile address/2:\r
-      u32 addr = ((code&0x3ff)<<5) + ty;\r
-      if (code & 0x1000) addr ^= 0x1e; // Y-flip\r
-\r
-      pal = (code>>9)&0x30; // shadow\r
-\r
-      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));\r
-    }\r
-\r
-    if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);\r
-    else               TileNorm_and(pd + dx, pack, pal);\r
-  }\r
+// Forced tile drawing, without any masking and blank handling\r
+#define DrawTileForced(mask,yshift,ymask,hpcode,cache) {               \\r
+    if (code!=oldcode) {                                               \\r
+      oldcode = code;                                                  \\r
+                                                                       \\r
+      /* Get tile address/2: */                                                \\r
+      u32 addr = ((code<<yshift)&0x7ff0) + ty;                         \\r
+      if (code & 0x1000) addr ^= ymask<<1; /* Y-flip */                        \\r
+                                                                       \\r
+      pal = ((code>>9)&0x30);                                          \\r
+      pal |= 0xc0; /* leave s/h bits untouched in pixel "and" */       \\r
+                                                                       \\r
+      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));                   \\r
+    }                                                                  \\r
+    if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);               \\r
+    else               TileNorm_and(pd + dx, pack, pal);               \\r
 }\r
 \r
-// XXX only duplicated to avoid ARM asm hassles\r
-static void DrawLayerForced(int plane_sh, int cellskip, int maxcells,\r
-  struct PicoEState *est)\r
-{\r
-  struct PicoVideo *pvid=&est->Pico->video;\r
-  const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid)\r
-  struct TileStrip ts;\r
-  int width, height, ymask;\r
-  int vscroll, htab;\r
+static DrawStripMaker(DrawStripForced, 4, 0x7, 0, DrawTileForced, 0);\r
 \r
-  ts.cells=maxcells;\r
+static DrawStripMaker(DrawStripInterlaceForced, 5, 0xf, 0, DrawTileForced, 0);\r
 \r
-  // Work out the TileStrip to draw\r
+static DrawStripVSRamMaker(DrawStripVSRamForced, 4, 0x7, 0, DrawTileForced, 0);\r
 \r
-  // Work out the name table size: 32 64 or 128 tiles (0-3)\r
-  width=pvid->reg[16];\r
-  height=(width>>4)&3; width&=3;\r
-\r
-  ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f)\r
-  ymask=(height<<8)|0xff;       // Y Mask in pixels\r
-  switch (width) {\r
-    case 1: ymask &= 0x1ff; break;\r
-    case 2: ymask =  0x007; break;\r
-    case 3: ymask =  0x0ff; break;\r
-  }\r
+static DrawStripVSRamMaker(DrawStripVSRamInterlaceForced, 5, 0xf, 0, DrawTileForced, 0);\r
 \r
-  // Find name table:\r
-  if (plane_sh&1) ts.nametab=(pvid->reg[4]&0x07)<<12; // B\r
-  else            ts.nametab=(pvid->reg[2]&0x38)<< 9; // A\r
-\r
-  htab=pvid->reg[13]<<9; // Horizontal scroll table address\r
-  switch (pvid->reg[11]&3) {\r
-    case 1: htab += (est->DrawScanline<<1) &  0x0f; break;\r
-    case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; // Offset by tile\r
-    case 3: htab += (est->DrawScanline<<1);         break; // Offset by line\r
-  }\r
-  htab+=plane_sh&1; // A or B\r
-\r
-  // Get horizontal scroll value, will be masked later\r
-  ts.hscroll = PicoMem.vram[htab & 0x7fff];\r
-\r
-  if((pvid->reg[12]&6) == 6) {\r
-    // interlace mode 2\r
-    vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value\r
-\r
-    // Find the line in the name table\r
-    ts.line=(vscroll+(est->DrawScanline<<1))&((ymask<<1)|1);\r
-    ts.nametab+=(ts.line>>4)<<shift[width];\r
-\r
-    DrawStripInterlaceForced(&ts);\r
-  } else if( pvid->reg[11]&4) {\r
-    // shit, we have 2-cell column based vscroll\r
-    // luckily this doesn't happen too often\r
-    ts.line=ymask|(shift[width]<<24); // save some stuff instead of line\r
-    // vscroll value for leftmost cells in case of hscroll not on 16px boundary\r
-    // XXX it's unclear what exactly the hw is doing. Continue reading where it\r
-    // stopped last seems to work best (H40: 0x50 (wrap->0x00), H32 0x40).\r
-    plane_sh |= PicoMem.vsram[(pvid->reg[12]&1?0x00:0x20) + (plane_sh&1)] << 16;\r
-    DrawStripVSRamForced(&ts, plane_sh, cellskip);\r
-  } else {\r
-    vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value\r
-\r
-    // Find the line in the name table\r
-    ts.line=(vscroll+est->DrawScanline)&ymask;\r
-    ts.nametab+=(ts.line>>3)<<shift[width];\r
-\r
-    DrawStripForced(&ts, cellskip);\r
-  }\r
-}\r
+static DrawLayerMaker(DrawLayerForced,DrawStripForced,DrawStripInterlaceForced,DrawStripVSRamForced,DrawStripVSRamInterlaceForced);\r
 \r
 static void DrawSpritesForced(unsigned char *sprited)\r
 {\r
@@ -1414,6 +1115,7 @@ static void DrawSpritesForced(unsigned char *sprited)
     sprite = Pico.est.HighPreSpr + offs;\r
     code = sprite[1];\r
     pal = (code>>9)&0x30;\r
+    pal |= 0xc0; // leave s/h bits untouched in pixel "and"\r
 \r
     if (code&0x800) fTileFunc = TileFlipSH_AS_and;\r
     else            fTileFunc = TileNormSH_AS_and;\r
@@ -1455,7 +1157,7 @@ static void DrawSpritesForced(unsigned char *sprited)
   }\r
 \r
   // anything not covered by a sprite is off \r
-  // XXX Titan hw notes say that transparent pixels remove shadow. Is this also\r
+  // TODO Titan hw notes say that transparent pixels remove shadow. Is this also\r
   // the case in areas where no sprites are displayed?\r
   for (cnt = 1; cnt < sizeof(mb)-1; cnt++)\r
     if (mb[cnt] == 0xff) {\r
@@ -1984,7 +1686,7 @@ static int DrawDisplay(int sh)
     DrawWindow(0, maxcells>>1, 1, sh, est);\r
   else if (hvwind == 2) {\r
     if (HighCacheA[0])\r
-      DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : -edge<<4, est);\r
+      DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : maxw, est);\r
     DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh, est);\r
   } else\r
     if (HighCacheA[0])\r
@@ -2005,10 +1707,11 @@ static int DrawDisplay(int sh)
 #ifdef FORCE\r
   if (pvid->debug_p & PVD_FORCE_B) {\r
     lflags = LF_PLANE_B | (sh<<1);\r
-    DrawLayerForced(lflags, 0, maxcells, est);\r
+    DrawLayerForced(lflags, NULL, 0, maxcells, est);\r
   } else if (pvid->debug_p & PVD_FORCE_A) {\r
+    // TODO what happens in windowed mode? \r
     lflags = LF_PLANE_A | (sh<<1);\r
-    DrawLayerForced(lflags, 0, maxcells, est);\r
+    DrawLayerForced(lflags, NULL, 0, maxcells, est);\r
   } else if (pvid->debug_p & PVD_FORCE_S)\r
     DrawSpritesForced(sprited);\r
 #endif\r