Implement I/O page, NMI and colour PROM, Galaxian can now boot
authorNick Downing <nick@ndcode.org>
Sun, 3 Jul 2022 12:16:24 +0000 (22:16 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 4 Jul 2022 04:59:20 +0000 (14:59 +1000)
emu_z80/emu_z80.c
galaxian/Makefile
galaxian/io_page.asm [new file with mode: 0644]
pacman/Makefile
pacman/io_page.asm [new file with mode: 0644]

index b936d44..7fdce2a 100644 (file)
 #define SAMPLES_PER_UPDATE 500
 
 #if GALAXIAN
-#define INT_VECTOR 0
-
 #define RAM_START 0x4000
 #define TILE_RAM 0x5000
-#define PALETTE_RAM 0x5400
 #define SPRITE_RAM 0x5800
 
 #define IO_PAGE 0x6000
+#define HW_INT_ENABLE 0x6031 // z80 7001
 #elif PACMAN
 #define INT_VECTOR 0
 
@@ -79,7 +77,8 @@
 #define SPRITE_CONFIG 0x4ff0
 
 #define IO_PAGE 0x5000
-#define SPRITE_COORDS 0x5060
+#define HW_INT_ENABLE 0x5100 // z80 5000
+#define SPRITE_COORDS 0x5160 // z80 5060
 #else // APPLE
 #define IO_PAGE 0xe000
 #define HW_KBD 0xe000 // R last key pressed + 128
 
 #define TRACE 0
 #define IO_TRACE 0
-#define MEM_TRACE 1
+#define MEM_TRACE 0
 
 extern char **environ;
 
@@ -300,8 +299,6 @@ uint8_t dos_lo;
 int usleep_count, exit_flag;
 
 #if GALAXIAN
-uint8_t int_vector;
-
 // just for now until we have galaxian audio
 #define C0X0_SOFT_SWITCH_TAPEOUT 4
 #define C0X0_SOFT_SWITCH_SPKR 8
@@ -314,7 +311,6 @@ int c0x0_soft_switches_buf_count;
 uint8_t c0x0_soft_switches_buf[C0X0_SOFT_SWITCHES_BUF_SIZE];
 #elif PACMAN
 uint8_t int_vector;
-uint8_t sprite_coords[0x10];
 
 // just for now until we have pacman audio
 #define C0X0_SOFT_SWITCH_TAPEOUT 4
@@ -662,7 +658,7 @@ void dos(char *line) {
 }
 
 uint8_t rb(void *userdata, uint16_t addr0) {
-#if GALAXIAN || PACMAN
+#if GALAXIAN
   int addr = addr0;
 
   if (addr < IO_PAGE) {
@@ -672,10 +668,26 @@ uint8_t rb(void *userdata, uint16_t addr0) {
 #endif
     return mem[addr];
   }
+  else if (addr < 0x8000 && (addr & 0x7f8) == 0) {
+    addr -= IO_PAGE;
+    addr = (addr & 7) | ((addr >> 8) & 0x18);
+    addr += IO_PAGE;
 #if MEM_TRACE
-  int pc = cpu.pc;
-  fprintf(stderr, "pc=%04x addr=%04x rd=??\n", pc, addr);
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
 #endif
+    return mem[addr];
+  }
+#elif PACMAN
+  int addr = addr0;
+
+  if (addr < IO_PAGE + 0x100) {
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+    return mem[addr];
+  }
 #else
   // for joystick, for now count memory accesses as proxy for cycles
   if (joystick_count < JOYSTICK_COUNT) {
@@ -1032,7 +1044,7 @@ uint8_t rb(void *userdata, uint16_t addr0) {
 }
 
 void wb(void *userdata, uint16_t addr0, uint8_t val) {
-#if GALAXIAN || PACMAN
+#if GALAXIAN
   int addr = addr0;
 
   if (addr < RAM_START)
@@ -1044,40 +1056,30 @@ void wb(void *userdata, uint16_t addr0, uint8_t val) {
 #endif
     mem[addr] = val;
   }
-  else if (addr < IO_PAGE + 0x100) {
+  else if (addr < 0x8000 && (addr & 0x7f8) == 0) {
+    addr -= IO_PAGE;
+    addr = (addr & 7) | ((addr >> 8) & 0x18);
+    addr += IO_PAGE | 0x20; // separate read and write registers
 #if MEM_TRACE
     int pc = cpu.pc;
-    fprintf(stderr, "pc=%04x addr=%04x wr=%02x (io)\n", pc, addr, val);
-#endif
-#if PACMAN
-    switch (addr) {
-    case SPRITE_COORDS: // 0x5060
-    case SPRITE_COORDS | 1: // 0x5061
-    case SPRITE_COORDS | 2: // 0x5062
-    case SPRITE_COORDS | 3: // 0x5063
-    case SPRITE_COORDS | 4: // 0x5064
-    case SPRITE_COORDS | 5: // 0x5065
-    case SPRITE_COORDS | 6: // 0x5066
-    case SPRITE_COORDS | 7: // 0x5067
-    case SPRITE_COORDS | 8: // 0x5068
-    case SPRITE_COORDS | 9: // 0x5069
-    case SPRITE_COORDS | 0xa: // 0x506a
-    case SPRITE_COORDS | 0xb: // 0x506b
-    case SPRITE_COORDS | 0xc: // 0x506c
-    case SPRITE_COORDS | 0xd: // 0x506d
-    case SPRITE_COORDS | 0xe: // 0x506e
-    case SPRITE_COORDS | 0xf: // 0x506f
-      sprite_coords[addr & 0xf] = val;
-      break;
-    }
+    fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
 #endif
+    mem[addr] = val;
   }
+#elif PACMAN
+  int addr = addr0;
+
+  if (addr < RAM_START)
+    ;
+  else if (addr < IO_PAGE + 0x100) {
+    if (addr >= IO_PAGE)
+      addr += 0x100; // separate read and write registers
 #if MEM_TRACE
-  else {
     int pc = cpu.pc;
-    fprintf(stderr, "pc=%04x addr=%04x wr=%02x (nop)\n", pc, addr, val);
-  }
+    fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
 #endif
+    mem[addr] = val;
+  }
 #else
   // for joystick, for now count memory accesses as proxy for cycles
   if (joystick_count < JOYSTICK_COUNT) {
@@ -1339,7 +1341,7 @@ void out(z80 *const z, uint8_t port, uint8_t val) {
 #endif
 
   switch (port) {
-#if GALAXIAN || PACMAN
+#if PACMAN
   case INT_VECTOR:
     int_vector = val;
     break;
@@ -1976,28 +1978,34 @@ int main(int argc, char **argv) {
 
 #if GALAXIAN
       // send z80 a vertical refresh interrupt
-      cpu.int_pending = true;
-      cpu.int_data = int_vector;
+      if (mem[HW_INT_ENABLE] & 1)
+        cpu.nmi_pending = true;
 
       // draw tiles
-      for (int i = 0; i < 32; ++i)
+      for (int i = 0; i < 32; ++i) {
+        int palette_base =
+          ((mem[i | SPRITE_RAM] & 7) << 2) |
+          ROM_GALAXIAN_CLR_ADDR;
         for (int j = 0; j < 28; ++j) {
           int offset = i + ((27 - j) << 5);
           int tile_base = 7 | (mem[TILE_RAM | offset] << 3);
-          int tile_base0 = tile_base | ROM_1H_ADDR;
-          int tile_base1 = tile_base | ROM_1K_ADDR;
-          int palette_base =
-            ((mem[PALETTE_RAM | offset] & 0x3f) << 2) | ROM_GALAXIAN_CLR_ADDR;
+          int tile_base0 = tile_base | ROM_1K_ADDR;
+          int tile_base1 = tile_base | ROM_1H_ADDR;
           for (int k = 0; k < 8; ++k) {
             int y = ((i << 3) | k) * WINDOW_Y_SCALE;
             for (int l = 0; l < 8; ++l) {
               int data0 = mem[l ^ tile_base0] << (k & 7);
               int data1 = mem[l ^ tile_base1] << (k & 7);
-              uint32_t rgb = palette[
-                mem[
-                  ((data0 & 0x80) >> 7) | ((data1 & 0x80) >> 6) | palette_base
-                ] & 0xf
-              ];
+              int colour = mem[
+                ((data0 & 0x80) >> 7) |
+                ((data1 & 0x80) >> 6) |
+                palette_base
+              ]; // approximately bbgggrrr
+              uint32_t rgb =
+                ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+                ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+                ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+                0xff000000;
               int x = ((j << 3) | l) * WINDOW_X_SCALE;
               for (int m = 0; m < WINDOW_Y_SCALE; ++m)
                 for (int n = 0; n < WINDOW_X_SCALE; ++n)
@@ -2005,6 +2013,7 @@ int main(int argc, char **argv) {
             }
           }
         }
+      }
 
       // draw sprites
       // from MAME /src/mame/video/galaxian.cpp:
@@ -2024,13 +2033,13 @@ int main(int argc, char **argv) {
           (!x_flip * 0x17) |
           (y_flip * 0x28) |
           ((data & 0x3f) << 5);
-        int sprite_base0 = sprite_base | ROM_1H_ADDR;
-        int sprite_base1 = sprite_base | ROM_1K_ADDR;
+        int sprite_base0 = sprite_base | ROM_1K_ADDR;
+        int sprite_base1 = sprite_base | ROM_1H_ADDR;
         int palette_base =
           ((mem[0x42 | (i << 2) | SPRITE_RAM] & 7) << 2) |
           ROM_GALAXIAN_CLR_ADDR;
-        int x = GALAXIAN_WIDTH + 15 - mem[0x43 | (i << 2) | SPRITE_RAM];
-        int y = GALAXIAN_HEIGHT - mem[0x40 | (i << 2) | SPRITE_RAM];
+        int x = mem[0x40 | (i << 2) | SPRITE_RAM] - 16;
+        int y = mem[0x43 | (i << 2) | SPRITE_RAM];
         for (int j = 0; j < 16; ++j) {
           int y1 = y + j;
           if (y1 >= 0 && y1 < GALAXIAN_HEIGHT) {
@@ -2044,13 +2053,16 @@ int main(int argc, char **argv) {
                   int data0 = mem[addr ^ sprite_base0] << shift;
                   int data1 = mem[addr ^ sprite_base1] << shift;
                   if ((data0 | data1) & 0x80) {
-                    uint32_t rgb = palette[
-                      mem[
-                        ((data0 & 0x80) >> 7) |
-                        ((data1 & 0x80) >> 6) |
-                        palette_base
-                      ] & 0xf
-                    ];
+                    int colour = mem[
+                      ((data0 & 0x80) >> 7) |
+                      ((data1 & 0x80) >> 6) |
+                      palette_base
+                    ]; // approximately bbgggrrr
+                    uint32_t rgb =
+                      ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+                      ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+                      ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+                      0xff000000;
                     x1 *= WINDOW_X_SCALE;
                     for (int l = 0; l < WINDOW_Y_SCALE; ++l)
                       for (int m = 0; m < WINDOW_X_SCALE; ++m)
@@ -2063,13 +2075,16 @@ int main(int argc, char **argv) {
                   int data0 = mem[addr ^ sprite_base0] >> shift;
                   int data1 = mem[addr ^ sprite_base1] >> shift;
                   if ((data0 | data1) & 1) {
-                    uint32_t rgb = palette[
-                      mem[
-                        ((data0 & 0x80) >> 7) |
-                        ((data1 & 0x80) >> 6) |
-                        palette_base
-                      ] & 0xf
-                    ];
+                    int colour = mem[
+                      (data0 & 1) ^
+                      ((data1 & 1) << 1) ^
+                      palette_base
+                    ]; // approximately bbgggrrr
+                    uint32_t rgb =
+                      ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+                      ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+                      ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+                      0xff000000;
                     x1 *= WINDOW_X_SCALE;
                     for (int l = 0; l < WINDOW_Y_SCALE; ++l)
                       for (int m = 0; m < WINDOW_X_SCALE; ++m)
@@ -2083,8 +2098,10 @@ int main(int argc, char **argv) {
       }
 #elif PACMAN
       // send z80 a vertical refresh interrupt
-      cpu.int_pending = true;
-      cpu.int_data = int_vector;
+      if (mem[HW_INT_ENABLE] & 1) {
+        cpu.int_pending = true;
+        cpu.int_data = int_vector;
+      }
 
       // draw tiles
       for (int i = 0; i < 36; ++i)
@@ -2096,9 +2113,9 @@ int main(int argc, char **argv) {
                 0x3a0 - 2 + i - (j << 5) :
                 0x1d - (34 << 5) + (i << 5) - j;
           int tile_base =
-            0xf | (mem[TILE_RAM | offset] << 4) | ROM_PACMAN_5E_ADDR;
+            0xf | (mem[offset | TILE_RAM] << 4) | ROM_PACMAN_5E_ADDR;
           int palette_base =
-            ((mem[PALETTE_RAM | offset] & 0x3f) << 2) | ROM_82S126_4A_ADDR;
+            ((mem[offset | PALETTE_RAM] & 0x3f) << 2) | ROM_82S126_4A_ADDR;
           for (int k = 0; k < 8; ++k) {
             int y = ((i << 3) | k) * WINDOW_Y_SCALE;
             for (int l = 0; l < 8; ++l) {
@@ -2129,8 +2146,8 @@ int main(int argc, char **argv) {
         int palette_base =
           ((mem[1 | (i << 1) | SPRITE_CONFIG] & 0x3f) << 2) |
           ROM_82S126_4A_ADDR;
-        int x = PACMAN_WIDTH + 15 - sprite_coords[i << 1];
-        int y = PACMAN_HEIGHT - 16 - sprite_coords[1 | (i << 1)];
+        int x = PACMAN_WIDTH + 15 - mem[(i << 1) | SPRITE_COORDS];
+        int y = PACMAN_HEIGHT - 16 - mem[1 | (i << 1) | SPRITE_COORDS];
         for (int j = 0; j < 16; ++j) {
           int y1 = y + j;
           if (y1 >= 0 && y1 < PACMAN_HEIGHT) {
index 346aafa..6578989 100644 (file)
@@ -1,8 +1,13 @@
+ASZ80=../asxv5pxx/asxmak/linux/exe/asz80
+ASLINK=../asxv5pxx/asxmak/linux/exe/aslink
+
 # need to install intelhex package in Python first:
 #   pip3 install --user intelhex
 BIN2HEX=bin2hex.py
 HEX2BIN=hex2bin.py
 
+IO_PAGE=0x5000
+
 # some ROMs are loaded into emulator addresses not accessible by software,
 # this is for convenience so we can build entire game from one source file
 ROM_GALMIDW_U_ADDR=0
@@ -26,7 +31,7 @@ galaxian.clr \
 
 all: galaxian0.ihx
 
-galaxian0.ihx: ${ROMS:%=%.ihx}
+galaxian0.ihx: ${ROMS:%=%.ihx} io_page.ihx
        hexmerge.py -o $@ $^
 
 galmidw.u.ihx: galmidw.u
@@ -58,5 +63,11 @@ ${ROMS}: ../orig/galaxian.zip
        unzip $<
        touch ${ROMS}
 
+io_page.ihx: io_page.rel
+       ${ASLINK} -n -m -u -i -b io_page=${IO_PAGE} $@ $^
+
+io_page.rel: io_page.asm
+       ${ASZ80} -l -o $<
+
 clean:
-       rm -f *.ihx ${ROMS}
+       rm -f *.hlr *.ihx *.lst *.map *.o *.rel *.rst ${ROMS}
diff --git a/galaxian/io_page.asm b/galaxian/io_page.asm
new file mode 100644 (file)
index 0000000..3eff672
--- /dev/null
@@ -0,0 +1,22 @@
+; we implement the I/O page as RAM, basically used as communication
+; area between the program and the emulator -- for example, if the
+; joystick moves, the emulator saves the new state in the I/O page,
+; then the program picks it up later using an ordinary memory read
+; this file contains the initial contents, e.g. to set DIP switches
+
+; unfortunately on Galaxian the I/O is very spread out, therefore
+; to conserve emulator memory we implement 8 bytes from each 0x800
+
+       .area   io_page
+
+       ; read
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6000 (z80 6000)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6008 (z80 6800)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6010 (z80 7000)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6018 (z80 7800)
+
+       ; write
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6020 (z80 6000)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6028 (z80 6800)
+       .db     0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff ; 6030 (z80 7000)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 6038 (z80 7800)
index 5ccfbc0..4847304 100644 (file)
@@ -1,8 +1,13 @@
+ASZ80=../asxv5pxx/asxmak/linux/exe/asz80
+ASLINK=../asxv5pxx/asxmak/linux/exe/aslink
+
 # need to install intelhex package in Python first:
 #   pip3 install --user intelhex
 BIN2HEX=bin2hex.py
 HEX2BIN=hex2bin.py
 
+IO_PAGE=0x5000
+
 # some ROMs are loaded into emulator addresses not accessible by software,
 # this is for convenience so we can build entire game from one source file
 ROM_PACMAN_6E_ADDR=0
@@ -30,7 +35,7 @@ pacman.5f
 
 all: pacman0.ihx
 
-pacman0.ihx: ${ROMS:%=%.ihx}
+pacman0.ihx: ${ROMS:%=%.ihx} io_page.ihx
        hexmerge.py -o $@ $^
 
 pacman.6e.ihx: pacman.6e
@@ -68,5 +73,11 @@ ${ROMS}: ../orig/pacman.zip
        unzip $<
        touch ${ROMS}
 
+io_page.ihx: io_page.rel
+       ${ASLINK} -n -m -u -i -b io_page=${IO_PAGE} $@ $^
+
+io_page.rel: io_page.asm
+       ${ASZ80} -l -o $<
+
 clean:
-       rm -f *.ihx ${ROMS}
+       rm -f *.hlr *.ihx *.lst *.map *.o *.rel *.rst ${ROMS}
diff --git a/pacman/io_page.asm b/pacman/io_page.asm
new file mode 100644 (file)
index 0000000..933bafe
--- /dev/null
@@ -0,0 +1,75 @@
+; we implement the I/O page as RAM, basically used as communication
+; area between the program and the emulator -- for example, if the
+; joystick moves, the emulator saves the new state in the I/O page,
+; then the program picks it up later using an ordinary memory read
+; this file contains the initial contents, e.g. to set DIP switches
+
+       .area   io_page
+
+       ; read
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5000
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5008
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5010
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5018
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5020
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5028
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5030
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5038
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5040
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5048
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5050
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5058
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5060
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5068
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5070
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5078
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5080
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5088
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5090
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5098
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50a0
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50a8
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50b0
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50b8
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50c0
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50c8
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50d0
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50d8
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50e0
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50e8
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50f0
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50f8
+
+       ; write
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5100 (z80 5000)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5108 (z80 5008)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5110 (z80 5010)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5118 (z80 5018)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5120 (z80 5020)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5128 (z80 5028)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5130 (z80 5030)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5138 (z80 5038)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5140 (z80 5040)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5148 (z80 5048)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5150 (z80 5050)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5158 (z80 5058)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5160 (z80 5060)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5168 (z80 5068)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5170 (z80 5070)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5178 (z80 5078)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5180 (z80 5080)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5188 (z80 5088)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5190 (z80 5090)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5198 (z80 5098)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51a0 (z80 50a0)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51a8 (z80 50a8)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51b0 (z80 50b0)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51b8 (z80 50b8)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51c0 (z80 50c0)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51c8 (z80 50c8)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51d0 (z80 50d0)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51d8 (z80 50d8)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51e0 (z80 50e0)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51e8 (z80 50e8)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51f0 (z80 50f0)
+       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51f8 (z80 50f8)