Add Donkey Kong emulation
authorNick Downing <nick@ndcode.org>
Wed, 13 Jul 2022 08:41:28 +0000 (18:41 +1000)
committerNick Downing <nick@ndcode.org>
Wed, 13 Jul 2022 14:06:29 +0000 (00:06 +1000)
.gitmodules
dkong/io_page.asm
doc/dkdasm [new submodule]
emu_z80/emu_z80.c

index b49042e..f16cd75 100644 (file)
@@ -4,3 +4,6 @@
 [submodule "emu_z80/z80"]
        path = emu_z80/z80
        url = https://github.com/nickd4/z80.git
+[submodule "doc/dkdasm"]
+       path = doc/dkdasm
+       url = https://github.com/furrykef/dkdasm
index 371e90b..92e21a5 100644 (file)
@@ -7,45 +7,45 @@
        .area   io_page
 
        ; read
-       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7800
-       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7808
+       .db     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7800
+       .db     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7808
        .ds     0x30
 
        ; write 
-       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7840 (z80 7800)
-       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7848 (z80 7808)
+       .db     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7840 (z80 7800)
+       .db     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7848 (z80 7808)
        .ds     0x30
 
        .ds     0x380
 
        ; read
-       .db     0xff                                    ; 7c00
+       .db     0x00                                    ; 7c00
        .ds     0x3f
 
        ; write
-       .db     0xff                                    ; 7c40 (z80 7c00)
+       .db     0x00                                    ; 7c40 (z80 7c00)
        .ds     0x3f
 
        ; read
-       .db     0xff                                    ; 7c80
+       .db     0x00                                    ; 7c80
        .ds     0x3f
 
        ; write
-       .db     0xff                                    ; 7cc0 (z80 7c80)
+       .db     0x00                                    ; 7cc0 (z80 7c80)
        .ds     0x3f
 
        ; read
-       .db     0xff                                    ; 7d00
+       .db     0x00                                    ; 7d00
        .ds     0x3f
 
        ; write
-       .db     0xff                                    ; 7d40 (z80 7d00)
+       .db     0x00                                    ; 7d40 (z80 7d00)
        .ds     0x3f
 
        ; read
-       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7d80
+       .db     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7d80
        .ds     0x38
 
        ; write
-       .db     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7dc0 (z80 7d80)
+       .db     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7dc0 (z80 7d80)
        .ds     0x38
diff --git a/doc/dkdasm b/doc/dkdasm
new file mode 160000 (submodule)
index 0000000..4d296c5
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 4d296c5737e768c35afdfa2bf64fcadea93a9677
index 5168485..7108a74 100644 (file)
 #include "stty_sane.h"
 #include "z80/z80.h"
 
-#define INVADERS 1
+#define DKONG 1
+#define INVADERS 0
 #define GALAXIAN 0
 #define PACMAN 0
 #define APPLE 0
 
-#if INVADERS
+#if DKONG
+#define DKONG_WIDTH 224
+#define DKONG_HEIGHT 256
+
+#define PADDED_WIDTH DKONG_WIDTH
+#define PADDED_HEIGHT DKONG_HEIGHT
+
+#define WINDOW_X_SCALE 3
+#define WINDOW_Y_SCALE 3
+#elif INVADERS
 #define INVADERS_WIDTH 224
 #define INVADERS_HEIGHT 256
 
 #define SAMPLES_PER_UPDATE 735 // 60 Hz @ 44100 Hz
 #endif
 
-#if INVADERS
+#if DKONG
+#define RAM_START 0x6000
+#define RAM_SIZE 0x1800
+
+#define SPRITE_RAM 0x6900
+#define TILE_RAM 0x7400
+
+#define IO_START 0x7800
+#define IO_SIZE 0x600
+
+#define HW_INT_ENABLE 0x7dc4 // z80 7d84
+#define HW_PALETTE_A 0x7dc6 // z80 7d86
+#define HW_PALETTE_B 0x7dc7 // z80 7d87
+#elif INVADERS
 #define INPUT_PORT0 0
 #define INPUT_PORT1 1
 #define INPUT_PORT2 2
 #define VIDEO_RAM 0x2400
 #elif GALAXIAN
 #define RAM_START 0x4000
-#define RAM_SIZE 0x1000
+#define RAM_SIZE 0x2000
 
 #define TILE_RAM 0x5000
 #define SPRITE_RAM 0x5800
@@ -249,7 +272,23 @@ uint32_t mono_palette[2] = {0xff000000, 0xffffffff};
 
 z80 cpu;
 
-#if INVADERS
+#if DKONG
+#define ROM_C_5ET_G_ADDR 0
+#define ROM_C_5CT_G_ADDR 0x1000
+#define ROM_C_5BT_G_ADDR 0x2000
+#define ROM_C_5AT_G_ADDR 0x3000
+#define ROM_C_2K_2J_ADDR 0x7e00
+#define ROM_V_5E_ADDR 0x7f00
+#define ROM_S_3I_B_ADDR 0x8000
+#define ROM_S_3J_B_ADDR 0x8800
+#define ROM_V_5H_B_ADDR 0xa000
+#define ROM_V_3PT_ADDR 0xa800
+#define ROM_L_4M_B_ADDR 0xb000
+#define ROM_L_4N_B_ADDR 0xb800
+#define ROM_L_4R_B_ADDR 0xc000
+#define ROM_L_4S_B_ADDR 0xc800
+#define MEM_SIZE 0xd000
+#elif INVADERS
 #define ROM_INVADERS_H_ADDR 0
 #define ROM_INVADERS_G_ADDR 0x800
 #define ROM_INVADERS_F_ADDR 0x1000
@@ -330,7 +369,20 @@ uint8_t usleep_lo;
 uint8_t dos_lo;
 int usleep_count, exit_flag;
 
-#if INVADERS
+#if DKONG
+uint8_t int_vector;
+
+// just for now until we have dkong audio
+#define C0X0_SOFT_SWITCH_TAPEOUT 4
+#define C0X0_SOFT_SWITCH_SPKR 8
+uint8_t c0x0_soft_switches = 0;
+
+// every n cycles, sample the tape and speaker outputs to here
+#define C0X0_SOFT_SWITCHES_BUF_SIZE 0x400 // next power of 2 >= 441 * 2
+int c0x0_soft_switches_buf_head;
+int c0x0_soft_switches_buf_count;
+uint8_t c0x0_soft_switches_buf[C0X0_SOFT_SWITCHES_BUF_SIZE];
+#elif INVADERS
 uint16_t shift_buffer;
 uint8_t shift_count;
 
@@ -704,7 +756,24 @@ void dos(char *line) {
 }
 
 uint8_t rb(void *userdata, uint16_t addr0) {
-#if INVADERS
+#if DKONG
+  int addr = addr0;
+
+  if (addr < IO_START) { // ROM, RAM
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+    return mem[addr];
+  }
+  if (addr < IO_START + IO_SIZE && (addr & 0x40) == 0) { // I/O
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+    return mem[addr];
+  }
+#elif INVADERS
   int addr = addr0;
 
   if (addr < RAM_START + RAM_SIZE) { // ROM, RAM
@@ -737,7 +806,7 @@ uint8_t rb(void *userdata, uint16_t addr0) {
 #elif PACMAN
   int addr = addr0;
 
-  if (addr < IO_START + 0x100) { // ROM, RAM, I/O
+  if (addr < IO_START + IO_SIZE) { // ROM, RAM, I/O
 #if MEM_TRACE
     int pc = cpu.pc;
     fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
@@ -1100,7 +1169,27 @@ uint8_t rb(void *userdata, uint16_t addr0) {
 }
 
 void wb(void *userdata, uint16_t addr0, uint8_t val) {
-#if INVADERS
+#if DKONG
+  int addr = addr0;
+
+  if (addr < RAM_START) // ROM
+    ;
+  else if (addr < IO_START) { // RAM
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
+#endif
+    mem[addr] = val;
+  }
+  else if (addr < IO_START + IO_SIZE && (addr & 0x40) == 0) { // RAM, I/O
+    addr |= 0x40; // separate read and write registers
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
+#endif
+    mem[addr] = val;
+  }
+#elif INVADERS
   int addr = addr0;
 
   if (addr < RAM_START) // ROM
@@ -1139,7 +1228,7 @@ void wb(void *userdata, uint16_t addr0, uint8_t val) {
 
   if (addr < RAM_START) // ROM
     ;
-  else if (addr < IO_START + 0x100) { // RAM, I/O
+  else if (addr < IO_START + IO_SIZE) { // RAM, I/O
     if (addr >= IO_START)
       addr += 0x100; // separate read and write registers
 #if MEM_TRACE
@@ -1510,7 +1599,7 @@ int main(int argc, char **argv) {
   bool timing = false;
   while (argn < argc) {
     if (strcmp(argv[argn], "--help") == 0) {
-#if GALAXIAN || PACMAN
+#if DKONG || INVADERS || GALAXIAN || PACMAN
       printf("usage: %s [--timing] [program.obj[,aNNNN] ...] [-- child-executable [child-argument ...]]\n", argv[0]);
 #else // APPLE
       printf("usage: %s [--cg-rom=file.bin] [--video-rom=file.bin] [--NN-rom=file.bin ...] [--timing] [program.obj[,aNNNN] ...] [-- child-executable [child-argument ...]]\n", argv[0]);
@@ -2061,7 +2150,108 @@ int main(int argc, char **argv) {
       SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
       SDL_RenderClear(renderer);
 
-#if INVADERS
+#if DKONG
+      // send z80 a vertical refresh interrupt
+      if (mem[HW_INT_ENABLE] & 1)
+        z80_gen_nmi(&cpu);
+
+      // draw tiles
+      int palette_base0 = 
+        ((mem[HW_PALETTE_A] & 1) << 6) |
+        ((mem[HW_PALETTE_B] & 1) << 7) |
+        ROM_C_2K_2J_ADDR;
+      for (int i = 0; i < 32; ++i)
+        for (int j = 0; j < 28; ++j) {
+          int palette_base1 =
+            ((mem[i | ((j & 0x1c) << 3) | ROM_V_5E_ADDR] & 0xf) << 2) |
+            palette_base0;
+          int tile_base =
+            7 |
+            (mem[i | ((29 - j) << 5) | TILE_RAM] << 3);
+          int tile_base0 = tile_base | ROM_V_5H_B_ADDR;
+          int tile_base1 = tile_base | ROM_V_3PT_ADDR;
+          for (int k = 0; k < 8; ++k) {
+            int y1 = (k | (i << 3)) * 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);
+              int colour = ~mem[
+                ((data0 & 0x80) >> 7) |
+                ((data1 & 0x80) >> 6) |
+                palette_base1
+              ]; // approximately rrrgggbb
+              uint32_t rgb =
+                ((((colour & 0xe0) * 0x49) & 0x3fc0) << 10) |
+                ((((colour & 0x1c) * 0x49) & 0x7f8) << 5) |
+                ((colour & 3) * 0x55) |
+                0xff000000;
+              int x1 = (l | (j << 3)) * WINDOW_X_SCALE;
+              for (int m = 0; m < WINDOW_Y_SCALE; ++m)
+                for (int n = 0; n < WINDOW_X_SCALE; ++n)
+                  frame[y1 + m][x1 + n] = rgb;
+            }
+          }
+        }
+
+      // draw sprites
+      // from MAME /src/mame/video/galaxian.cpp:
+      //   spriteram[0x40] = vertical position of sprite 0
+      //   spriteram[0x41] = picture number and H/V flip of sprite 0
+      //   spriteram[0x42] = color of sprite 0
+      //   spriteram[0x43] = horizontal position of sprite 0
+      //   ...
+      //   spriteram[0x61] = vertical position of shell 0
+      //   spriteram[0x63] = horizontal count until shell 0 starts rendering
+      //   ...
+      for (int i = 0x7f; i >= 0; --i) {
+        int data1 = mem[1 | (i << 2) | SPRITE_RAM];
+        int data2 = mem[2 | (i << 2) | SPRITE_RAM];
+        bool x_flip = (data1 >> 7) & 1;
+        bool y_flip = (data2 >> 7) & 1;
+        int sprite_base =
+          (!x_flip * 0xf) |
+          (y_flip * 0x800) |
+          ((data1 & 0x7f) << 4);
+        int shift_flip = y_flip * 7;
+        int sprite_base0 = sprite_base | ROM_L_4M_B_ADDR;
+        int sprite_base1 = sprite_base | ROM_L_4R_B_ADDR;
+        int palette_base1 = ((data2 & 0xf) << 2) | palette_base0;
+        int x = mem[(i << 2) | SPRITE_RAM] - 23;
+        int y = mem[3 | (i << 2) | SPRITE_RAM] - 8;
+        for (int j = 0; j < 16; ++j) {
+          int y1 = y + j;
+          if (y1 >= 0 && y1 < DKONG_HEIGHT) {
+            y1 *= WINDOW_Y_SCALE;
+            for (int k = 0; k < 16; ++k) {
+              int x1 = x + k;
+              if (x1 >= 0 && x1 < DKONG_WIDTH) {
+                int addr = k ^ ((j & 8) << 8);
+                int shift = (j & 7) ^ shift_flip;
+                int data0 = mem[addr ^ sprite_base0] << shift;
+                int data1 = mem[addr ^ sprite_base1] << shift;
+                if ((data0 | data1) & 0x80) {
+                  int colour = ~mem[
+                    ((data0 & 0x80) >> 7) |
+                    ((data1 & 0x80) >> 6) |
+                    palette_base1
+                  ]; // approximately rrrgggbb
+                  uint32_t rgb =
+                    ((((colour & 0xe0) * 0x49) & 0x3fc0) << 10) |
+                    ((((colour & 0x1c) * 0x49) & 0x7f8) << 5) |
+                    ((colour & 3) * 0x55) |
+                    0xff000000;
+ //rgb = 0xff808080 + i * 0x101010;
+                  x1 *= WINDOW_X_SCALE;
+                  for (int l = 0; l < WINDOW_Y_SCALE; ++l)
+                    for (int m = 0; m < WINDOW_X_SCALE; ++m)
+                      frame[y1 + l][x1 + m] = rgb;
+                }
+              }
+            }
+          }
+        }
+      }
+#elif INVADERS
       // send z80 a vertical refresh interrupt
       int j0, j1;
       if (frame_half == false) {
@@ -2207,8 +2397,9 @@ int main(int argc, char **argv) {
         bool y_flip = (data >> 7) & 1;
         int sprite_base =
           (!x_flip * 0x17) |
-          (y_flip * 0x28) |
+          (y_flip * 8) |
           ((data & 0x3f) << 5);
+        int shift_flip = y_flip * 7;
         int sprite_base0 = sprite_base | ROM_1K_ADDR;
         int sprite_base1 = sprite_base | ROM_1H_ADDR;
         int palette_base =
@@ -2223,51 +2414,26 @@ int main(int argc, char **argv) {
             for (int k = 0; k < 16; ++k) {
               int x1 = x + k;
               if (x1 >= 0 && x1 < GALAXIAN_WIDTH) {
-                if (!y_flip) {
-                  int addr = (k & 7) ^ (j & 8) ^ ((k & 8) << 1);
-                  int shift = j & 7;
-                  int data0 = mem[addr ^ sprite_base0] << shift;
-                  int data1 = mem[addr ^ sprite_base1] << shift;
-                  if ((data0 | data1) & 0x80) {
-                    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) >> 6) | // 0x3fc0 >> 6
-                      0xff000000;
- //rgb = 0xff808080 + i * 0x101010;
-                    x1 *= WINDOW_X_SCALE;
-                    for (int l = 0; l < WINDOW_Y_SCALE; ++l)
-                      for (int m = 0; m < WINDOW_X_SCALE; ++m)
-                        frame[y1 + l][x1 + m] = rgb;
-                  }
-                }
-                else {
-                  int addr = (k & 7) ^ (j & 8) ^ ((k & 8) << 1);
-                  int shift = j & 7;
-                  int data0 = mem[addr ^ sprite_base0] >> shift;
-                  int data1 = mem[addr ^ sprite_base1] >> shift;
-                  if ((data0 | data1) & 1) {
-                    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) >> 6) | // 0x3fc0 >> 6
-                      0xff000000;
+                int addr = (k & 7) ^ (j & 8) ^ ((k & 8) << 1);
+                int shift = (j & 7) ^ shift_flip;
+                int data0 = mem[addr ^ sprite_base0] << shift;
+                int data1 = mem[addr ^ sprite_base1] << shift;
+                if ((data0 | data1) & 0x80) {
+                  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) >> 6) | // 0x3fc0 >> 6
+                    0xff000000;
  //rgb = 0xff808080 + i * 0x101010;
-                    x1 *= WINDOW_X_SCALE;
-                    for (int l = 0; l < WINDOW_Y_SCALE; ++l)
-                      for (int m = 0; m < WINDOW_X_SCALE; ++m)
-                        frame[y1 + l][x1 + m] = rgb;
-                  }
+                  x1 *= WINDOW_X_SCALE;
+                  for (int l = 0; l < WINDOW_Y_SCALE; ++l)
+                    for (int m = 0; m < WINDOW_X_SCALE; ++m)
+                      frame[y1 + l][x1 + m] = rgb;
                 }
               }
             }
@@ -2347,6 +2513,8 @@ int main(int argc, char **argv) {
           (y_flip * 0x18) |
           ((data & 0xfc) << 4) |
           ROM_PACMAN_5F_ADDR;
+        int y_cycle = 4 - (y_flip << 3);
+        int shift_flip = y_flip * 3;
         int palette_base =
           ((mem[1 | (i << 1) | SPRITE_CONFIG] & 0x3f) << 2) |
           ROM_82S126_4A_ADDR;
@@ -2359,61 +2527,31 @@ int main(int argc, char **argv) {
             for (int k = 0; k < 16; ++k) {
               int x1 = x + k;
               if (x1 >= 0 && x1 < PACMAN_WIDTH) {
-                if (!y_flip) {
-                  int data = mem[
-                    (k & 7) ^
-                    (((j + 4) & 0xc) << 1) ^
-                    ((k & 8) << 2) ^
-                    sprite_base
-                  ] << (j & 3);
-                  int colour = mem[
-                    ((data & 8) >> 3) |
-                    ((data & 0x80) >> 6) |
-                    palette_base
-                  ] & 0x1f; // first stage lookup
-                  if (colour) {
-                    colour = mem[
-                      colour | ROM_82S123_7F_ADDR
-                    ]; // second stage lookup, approximately bbgggrrr
-                    uint32_t rgb =
-                      ((((colour & 7) * 0x49) & 0x1fe) << 15) |
-                      ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
-                      (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
-                      0xff000000;
- //rgb = 0xff808080 + i * 0x101010;
-                    x1 *= WINDOW_X_SCALE;
-                    for (int l = 0; l < WINDOW_Y_SCALE; ++l)
-                      for (int m = 0; m < WINDOW_X_SCALE; ++m)
-                        frame[y1 + l][x1 + m] = rgb;
-                  }
-                }
-                else {
-                  int data = mem[
-                    (k & 7) ^
-                    (((j - 4) & 0xc) << 1) ^
-                    ((k & 8) << 2) ^
-                    sprite_base
-                  ] >> (j & 3);
-                  int colour = mem[
-                    (data & 1) |
-                    ((data & 0x10) >> 3) |
-                    palette_base
-                  ] & 0x1f; // first stage lookup
-                  if (colour) {
-                    colour = mem[
-                      colour | ROM_82S123_7F_ADDR
-                    ]; // second stage lookup, approximately bbgggrrr
-                    uint32_t rgb =
-                      ((((colour & 7) * 0x49) & 0x1fe) << 15) |
-                      ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
-                      (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
-                      0xff000000;
+                int data = mem[
+                  (k & 7) ^
+                  (((j + y_cycle) & 0xc) << 1) ^
+                  ((k & 8) << 2) ^
+                  sprite_base
+                ] << ((j & 3) ^ shift_flip);
+                int colour = mem[
+                  ((data & 8) >> 3) |
+                  ((data & 0x80) >> 6) |
+                  palette_base
+                ] & 0x1f; // first stage lookup
+                if (colour) {
+                  colour = mem[
+                    colour | ROM_82S123_7F_ADDR
+                  ]; // second stage lookup, approximately bbgggrrr
+                  uint32_t rgb =
+                    ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+                    ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+                    (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
+                    0xff000000;
  //rgb = 0xff808080 + i * 0x101010;
-                    x1 *= WINDOW_X_SCALE;
-                    for (int l = 0; l < WINDOW_Y_SCALE; ++l)
-                      for (int m = 0; m < WINDOW_X_SCALE; ++m)
-                        frame[y1 + l][x1 + m] = rgb;
-                  }
+                  x1 *= WINDOW_X_SCALE;
+                  for (int l = 0; l < WINDOW_Y_SCALE; ++l)
+                    for (int m = 0; m < WINDOW_X_SCALE; ++m)
+                      frame[y1 + l][x1 + m] = rgb;
                 }
               }
             }