Add my starfield generator (seems to blink slightly too fast)
authorNick Downing <nick@ndcode.org>
Sun, 3 Jul 2022 16:24:33 +0000 (02:24 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 4 Jul 2022 04:59:23 +0000 (14:59 +1000)
emu_z80/emu_z80.c

index 3f6eb9b..9004d70 100644 (file)
@@ -58,8 +58,8 @@
 #define WINDOW_WIDTH (PADDED_WIDTH * WINDOW_X_SCALE)
 #define WINDOW_HEIGHT (PADDED_HEIGHT * WINDOW_Y_SCALE)
 
-#define CYCLES_PER_SAMPLE 34 // 44100 Hz @ 1.5 MHz
-#define SAMPLES_PER_UPDATE 500
+#define CYCLES_PER_SAMPLE 68 // 44100 Hz @ 3 MHz
+#define SAMPLES_PER_UPDATE 735 // 60 Hz @ 44100 Hz
 
 #if GALAXIAN
 #define RAM_START 0x4000
@@ -68,6 +68,7 @@
 
 #define IO_PAGE 0x6000
 #define HW_INT_ENABLE 0x6031 // z80 7001
+#define HW_STARS_ENABLE 0x6034 // z80 7004
 #elif PACMAN
 #define INT_VECTOR 0
 
@@ -1981,6 +1982,49 @@ int main(int argc, char **argv) {
       if (mem[HW_INT_ENABLE] & 1)
         cpu.nmi_pending = true;
 
+      // draw stars
+      if (mem[HW_STARS_ENABLE] & 1) {
+        static uint32_t lfsr0 = 0xffffffffU;
+        static int blink_state = 0;
+        static const uint32_t blink_table[4] =
+          {0x4000, 0x1000, 0x7e00, 0x7e00};
+
+        // stars are drawn when (lfsr & 0x1ff) == 1
+        // the colour comes from (lfsr >> 9) & 0x3f
+        // but just for fun we implement our own LFSR
+        // stars are suppressed at certain times, based on
+        // the blink state and certain of the colour bits
+        uint32_t lfsr = lfsr0;
+        for (int i = 0; i < GALAXIAN_WIDTH; ++i) {
+          int x = i * WINDOW_X_SCALE;
+          for (int j = GALAXIAN_HEIGHT * 2 - 1; j >= 0; --j) {
+            int y0 = (j * WINDOW_Y_SCALE) >> 1;
+            int y1 = ((j + 1) * WINDOW_Y_SCALE) >> 1;
+            uint32_t rgb = 0xff000000;
+            if (
+              (lfsr & 0x1ff) == 1 &&
+              ((i ^ (j >> 3)) & 1) &&
+              ((blink_state & 0x300) != 0x200 || (i & 2) != 0) &&
+              (lfsr & blink_table[blink_state >> 8])
+            )
+              rgb =
+                ((((lfsr & 0x600) * 0x55) & 0x1fc00) << 6) |
+                ((((lfsr & 0x1800) * 0x55) & 0x7f000) >> 4) |
+                ((((lfsr & 0x6000) * 0x55) & 0x1fc000) >> 14) |
+                0xff808080;
+            for (int k = y0; k < y1; ++k)
+              for (int l = 0; l < WINDOW_X_SCALE; ++l)
+                frame[k][x + l] = rgb;
+            lfsr = (lfsr >> 1) ^ ((lfsr & 1) * 0xedb88320U);
+          }
+        }
+
+        lfsr0 = (lfsr0 >> 1) ^ ((lfsr0 & 1) * 0xedb88320U);
+        blink_state = (blink_state + 11) & 0x3ff;
+      }
+      else
+        memset(frame, 0, WINDOW_HEIGHT * WINDOW_WIDTH * sizeof(uint32_t));
+
       // draw tiles
       for (int i = 0; i < 32; ++i) {
         int scroll = mem[(i << 1) | SPRITE_RAM] + 0x10;
@@ -2005,20 +2049,22 @@ int main(int argc, char **argv) {
               if (x1 >= 0 && x1 < GALAXIAN_WIDTH) {
                 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_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 m = 0; m < WINDOW_Y_SCALE; ++m)
-                  for (int n = 0; n < WINDOW_X_SCALE; ++n)
-                    frame[y1 + m][x1 + n] = rgb;
+                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;
+                  x1 *= 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;
+                }
               }
             }
           }
@@ -2071,7 +2117,7 @@ int main(int argc, char **argv) {
                     uint32_t rgb =
                       ((((colour & 7) * 0x49) & 0x1fe) << 15) |
                       ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
-                      ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+                      (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
                       0xff000000;
                     x1 *= WINDOW_X_SCALE;
                     for (int l = 0; l < WINDOW_Y_SCALE; ++l)
@@ -2093,7 +2139,7 @@ int main(int argc, char **argv) {
                     uint32_t rgb =
                       ((((colour & 7) * 0x49) & 0x1fe) << 15) |
                       ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
-                      ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+                      (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
                       0xff000000;
                     x1 *= WINDOW_X_SCALE;
                     for (int l = 0; l < WINDOW_Y_SCALE; ++l)