static void vdp_reg_w()

in cores/genesis/core/vdp_ctrl.c [1453:2055]


static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles)
{
#ifdef LOGVDP
  error("[%d(%d)][%d(%d)] VDP register %d write -> 0x%x (%x)\n", v_counter, (v_counter + (cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, cycles, cycles%MCYCLES_PER_LINE, r, d, m68k_get_reg(M68K_REG_PC));
#endif

  /* VDP registers #11 to #23 cannot be updated in Mode 4 (Captain Planet & Avengers, Bass Master Classic Pro Edition) */
  if (!(reg[1] & 4) && (r > 10))
  {
    return;
  }

  switch(r)
  {
    case 0: /* CTRL #1 */
    {
      /* Look for changed bits */
      r = d ^ reg[0];
      reg[0] = d;

      /* Line Interrupt */
      if (r & hint_pending)
      {
        /* Update IRQ status */
        if (reg[1] & vint_pending)
        {
          set_irq_line(6);
        }
        else if (d & 0x10)
        {
          set_irq_line_delay(4);
        }
        else
        {
          set_irq_line(0);
        }
      }

      /* Palette selection */
      if (r & 0x04)
      {
        /* Mega Drive VDP only */
        if (system_hw & SYSTEM_MD)
        {
          /* Reset color palette */
          int i;
          if (reg[1] & 0x04)
          {
            /* Mode 5 */
            color_update_m5(0x00, *(uint16 *)&cram[border << 1]);
            for (i = 1; i < 0x40; i++)
            {
              color_update_m5(i, *(uint16 *)&cram[i << 1]);
            }
          }
          else
          {
            /* Mode 4 */
            for (i = 0; i < 0x20; i++)
            {
              color_update_m4(i, *(uint16 *)&cram[i << 1]);
            }
            color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);
          }
        }
      }

      /* HVC latch (Sunset Riders, Lightgun games) */
      if (r & 0x02)
      {
        /* Mega Drive VDP only */
        if (system_hw & SYSTEM_MD)
        {
          /* Mode 5 only */
          if (reg[1] & 0x04)
          {
            if (d & 0x02)
            {
              /* Latch current HVC */
              hvc_latch = vdp_hvc_r(cycles) | 0x10000;
            }
            else
            {
              /* Free-running HVC */
              hvc_latch = 0;
            }
          }
        }
      }
      break;
    }

    case 1: /* CTRL #2 */
    {
      /* Look for changed bits */
      r = d ^ reg[1];
      reg[1] = d;

      /* 4K/16K address decoding */
      if (r & 0x80)
      {
        /* original TMS99xx hardware only (fixes Magical Kid Wiz) */
        if (system_hw == SYSTEM_SG)
        {
          int i;
          
          /* make temporary copy of 16KB VRAM */
          memcpy(vram + 0x4000, vram, 0x4000);

          /* re-arrange 16KB VRAM address decoding */
          if (d & 0x80)
          {
            /* 4K->16K address decoding */
            for (i=0; i<0x4000; i+=2)
            {
              *(uint16 *)(vram + ((i & 0x203F) | ((i << 6) & 0x1000) | ((i >> 1) & 0xFC0))) = *(uint16 *)(vram + 0x4000 + i);
            }
          }
          else
          {
            /* 16K->4K address decoding */
            for (i=0; i<0x4000; i+=2)
            {
              *(uint16 *)(vram + ((i & 0x203F) | ((i >> 6) & 0x40) | ((i << 1) & 0x1F80))) = *(uint16 *)(vram + 0x4000 + i);
            }
          }
        }
      }

      /* Display status (modified during active display) */
      if ((r & 0x40) && (v_counter < bitmap.viewport.h))
      {
        /* Cycle offset vs HBLANK */
        int offset = cycles - mcycles_vdp;
        if (offset <= 860)
        {
          /* Sprite rendering is limited if display was disabled during HBLANK (Mickey Mania 3d level, Overdrive Demo) */
          if (d & 0x40)
          {
            /* NB: This is not 100% accurate. On real hardware, the maximal number of rendered sprites pixels */
            /* for the current line (normally 256 or 320 pixels) but also the maximal number of pre-processed */
            /* sprites for the next line (normally 64 or 80 sprites) are both reduced depending on the amount */
            /* of cycles spent with display disabled. Here we only reduce them by a fixed amount when display */
            /* has been reenabled after a specific point within HBLANK. */
            if (offset > 360)
            {
              max_sprite_pixels = 128;
            }
          }

          /* Redraw entire line (Legend of Galahad, Lemmings 2, Formula One, Kawasaki Super Bike, Deadly Moves,...) */
          render_line(v_counter);

          /* Restore default */
          max_sprite_pixels = 256 + ((reg[12] & 1) << 6);
        }
        else if (system_hw & SYSTEM_MD)
        {
          /* Active pixel offset  */
          if (reg[12] & 1)
          {
            /* dot clock = MCLK / 8 */
            offset = ((offset - 860) / 8) + 16;
          }
          else
          {
            /* dot clock = MCLK / 10 */
            offset = ((offset - 860) / 10) + 16;
          }

          /* Line is partially blanked (Nigel Mansell's World Championship Racing , Ren & Stimpy Show, ...) */
          if (offset < bitmap.viewport.w)
          {
            if (d & 0x40)
            {
              render_line(v_counter);
              blank_line(v_counter, 0, offset);
            }
            else
            {
              blank_line(v_counter, offset, bitmap.viewport.w - offset);
            }
          }
        }
      }

      /* Frame Interrupt */
      if (r & vint_pending)
      {
        /* Update IRQ status */
        if (d & 0x20) 
        {
          set_irq_line_delay(6);
        }
        else if (reg[0] & hint_pending)
        {
          set_irq_line(4);
        }
        else
        {
          set_irq_line(0);
        }
      }

      /* Active display height */
      if (r & 0x08)
      {
        /* Mega Drive VDP only */
        if (system_hw & SYSTEM_MD)
        {
          /* Mode 5 only */
          if (d & 0x04)
          {
            /* Changes should be applied on next frame */
            bitmap.viewport.changed |= 2;

            /* Update vertical counter max value */
            vc_max = vc_table[(d >> 2) & 3][vdp_pal];
          }
        }
      }

      /* Rendering mode */
      if (r & 0x04)
      {
        /* Mega Drive VDP only */
        if (system_hw & SYSTEM_MD)
        {
          int i;
          if (d & 0x04)
          {
            /* Mode 5 rendering */
            parse_satb = parse_satb_m5;
            update_bg_pattern_cache = update_bg_pattern_cache_m5;
            if (im2_flag)
            {
              render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;
              render_obj = (reg[12] & 0x08) ? render_obj_m5_im2_ste : render_obj_m5_im2;
            }
            else
            {
              render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;
              render_obj = (reg[12] & 0x08) ? render_obj_m5_ste : render_obj_m5;
            }

            /* Reset color palette */
            color_update_m5(0x00, *(uint16 *)&cram[border << 1]);
            for (i = 1; i < 0x40; i++)
            {
              color_update_m5(i, *(uint16 *)&cram[i << 1]);
            }

            /* Mode 5 bus access */
            vdp_68k_data_w = vdp_68k_data_w_m5;
            vdp_z80_data_w = vdp_z80_data_w_m5;
            vdp_68k_data_r = vdp_68k_data_r_m5;
            vdp_z80_data_r = vdp_z80_data_r_m5;

            /* Clear HVC latched value */
            hvc_latch = 0;

            /* Check if HVC latch bit is set */
            if (reg[0] & 0x02)
            {
              /* Latch current HVC */
              hvc_latch = vdp_hvc_r(cycles) | 0x10000;
            }

            /* max tiles to invalidate */
            bg_list_index = 0x800;
          }
          else
          {
            /* Mode 4 rendering */
            parse_satb = parse_satb_m4;
            update_bg_pattern_cache = update_bg_pattern_cache_m4;
            render_bg = render_bg_m4;
            render_obj = render_obj_m4;

            /* Reset color palette */
            for (i = 0; i < 0x20; i++)
            {
              color_update_m4(i, *(uint16 *)&cram[i << 1]);
            }
            color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);

            /* Mode 4 bus access */
            vdp_68k_data_w = vdp_68k_data_w_m4;
            vdp_z80_data_w = vdp_z80_data_w_m4;
            vdp_68k_data_r = vdp_68k_data_r_m4;
            vdp_z80_data_r = vdp_z80_data_r_m4;

            /* Latch current HVC */
            hvc_latch = vdp_hvc_r(cycles) | 0x10000;

            /* max tiles to invalidate */
            bg_list_index = 0x200;
          }

          /* Invalidate pattern cache */
          for (i=0;i<bg_list_index;i++) 
          {
            bg_name_list[i] = i;
            bg_name_dirty[i] = 0xFF;
          }

          /* Update vertical counter max value */
          vc_max = vc_table[(d >> 2) & 3][vdp_pal];

          /* Display height change should be applied on next frame */
          bitmap.viewport.changed |= 2; 
        }
        else
        {
          /* No effect (cleared to avoid mode 5 detection elsewhere) */
          reg[1] &= ~0x04;
        }
      }
      break;
    }

    case 2: /* Plane A Name Table Base */
    {
      reg[2] = d;
      ntab = (d << 10) & 0xE000;

      /* Plane A Name Table Base changed during HBLANK */
      if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))
      {
        /* render entire line */
        render_line(v_counter);
      }
      break;
    }

    case 3: /* Window Plane Name Table Base */
    {
      reg[3] = d;
      if (reg[12] & 0x01)
      {
        ntwb = (d << 10) & 0xF000;
      }
      else
      {
        ntwb = (d << 10) & 0xF800;
      }

      /* Window Plane Name Table Base changed during HBLANK */
      if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))
      {
        /* render entire line */
        render_line(v_counter);
      }
      break;
    }

    case 4: /* Plane B Name Table Base */
    {
      reg[4] = d;
      ntbb = (d << 13) & 0xE000;

      /* Plane B Name Table Base changed during HBLANK (Adventures of Batman & Robin) */
      if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))
      {
        /* render entire line */
        render_line(v_counter);
      }

      break;
    }

    case 5: /* Sprite Attribute Table Base */
    {
      reg[5] = d;
      satb = (d << 9) & sat_base_mask;
      break;
    }

    case 7: /* Backdrop color */
    {
      reg[7] = d;

      /* Check if backdrop color changed */
      d &= 0x3F;

      if (d != border)
      {
        /* Update backdrop color */
        border = d;

        /* Reset palette entry */
        if (reg[1] & 4)
        {
          /* Mode 5 */
          color_update_m5(0x00, *(uint16 *)&cram[d << 1]);
        }
        else
        {
          /* Mode 4 */
          color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (d & 0x0F)) << 1]);
        }

        /* Backdrop color modified during HBLANK (Road Rash 1,2,3)*/
        if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))
        {
          /* remap entire line */
          remap_line(v_counter);
        }
      }
      break;
    }

    case 8:   /* Horizontal Scroll (Mode 4 only) */
    {
      /* H-Scroll is latched at HCount 0xF3, HCount 0xF6 on MD */
      /* Line starts at HCount 0xF4, HCount 0xF6 on MD */
      if (system_hw < SYSTEM_MD)
      {
        cycles = cycles + 15;
      }

      /* Check if H-Scroll has already been latched */
      if ((cycles - mcycles_vdp) >= MCYCLES_PER_LINE)
      {
        /* update line counter */
        int line = (v_counter + 1) % lines_per_frame;

        /* check if we are within active display range */
        if ((line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special & HW_3D_GLASSES))
        {
          /* update VCounter to indicate next line has already been rendered */
          v_counter = line;

          /* render next line before updating H-Scroll */
          render_line(line);
        }
      }

      reg[8] = d;
      break;
    }

    case 11:  /* CTRL #3 */
    {
      reg[11] = d;

      /* Horizontal scrolling mode */
      hscroll_mask = hscroll_mask_table[d & 0x03];

      /* Vertical Scrolling mode */
      if (d & 0x04)
      {
        render_bg = im2_flag ? render_bg_m5_im2_vs : render_bg_m5_vs;
      }
      else
      {
        render_bg = im2_flag ? render_bg_m5_im2 : render_bg_m5;
      }
      break;
    }

    case 12:  /* CTRL #4 */
    {
      /* Look for changed bits */
      r = d ^ reg[12];
      reg[12] = d;

      /* Shadow & Highlight mode */
      if (r & 0x08)
      {
        /* Reset color palette */
        int i;
        color_update_m5(0x00, *(uint16 *)&cram[border << 1]);
        for (i = 1; i < 0x40; i++)
        {
          color_update_m5(i, *(uint16 *)&cram[i << 1]);
        }

        /* Update sprite rendering function */
        if (d & 0x08)
        {
          render_obj = im2_flag ? render_obj_m5_im2_ste : render_obj_m5_ste;
        }
        else
        {
          render_obj = im2_flag ? render_obj_m5_im2 : render_obj_m5;
        }
      }

      /* Interlaced modes */
      if (r & 0x06)
      {
        /* changes should be applied on next frame */
        bitmap.viewport.changed |= 2;
      }

      /* Active display width */
      if (r & 0x01)
      {
        /* FIFO access slots timings depend on active width */
        if (fifo_slots)
        {
          /* Synchronize VDP FIFO */
          vdp_fifo_update(cycles);
        }

        if (d & 0x01)
        {
          /* Update display-dependant registers */
          ntwb = (reg[3] << 10) & 0xF000;
          satb = (reg[5] << 9) & 0xFC00;
          sat_base_mask = 0xFC00;
          sat_addr_mask = 0x03FF;

          /* Update HC table */
          hctab = cycle2hc40;

          /* Update clipping */
          window_clip(reg[17], 1);

          /* Update max sprite pixels per line*/
          max_sprite_pixels = 320;

          /* FIFO access slots timings */
          fifo_timing = (int *)fifo_timing_h40;
        }
        else
        {
          /* Update display-dependant registers */
          ntwb = (reg[3] << 10) & 0xF800;
          satb = (reg[5] << 9) & 0xFE00;
          sat_base_mask = 0xFE00;
          sat_addr_mask = 0x01FF;

          /* Update HC table */
          hctab = cycle2hc32;

          /* Update clipping */
          window_clip(reg[17], 0);

          /* Update max sprite pixels per line*/
          max_sprite_pixels = 256;

          /* FIFO access slots timings */
          fifo_timing = (int *)fifo_timing_h32;
        }

        /* Update active screen width */
        if (v_counter >= bitmap.viewport.h)
        {
          /* Active screen width modified during VBLANK will be applied on upcoming frame */
          bitmap.viewport.w = max_sprite_pixels;
        }
        else if ((v_counter == 0) && (cycles <= (mcycles_vdp + 860)))
        {
          /* Active screen width modified during first line HBLANK (Bugs Bunny in Double Trouble) */
          bitmap.viewport.w = max_sprite_pixels;

          /* Redraw first line */
          render_line(0);
        }
        else
        {
          /* Screen width changes during active display (Golden Axe 3 intro, Ultraverse Prime) */
          /* should be applied on next frame since backend rendered framebuffer width is fixed */
          /* and can not be modified mid-frame. This is not 100% accurate but games generally  */
          /* do this where the screen is blanked so it is likely unnoticeable. */
          bitmap.viewport.changed |= 2;
        }
      }
      break;
    }

    case 13: /* HScroll Base Address */
    {
      reg[13] = d;
      hscb = (d << 10) & 0xFC00;
      break;
    }

    case 16: /* Playfield size */
    {
      reg[16] = d;
      playfield_shift = shift_table[(d & 3)];
      playfield_col_mask = col_mask_table[(d & 3)];
      playfield_row_mask = row_mask_table[(d >> 4) & 3];
      break;
    }

    case 17: /* Window/Plane A vertical clipping */
    {
      reg[17] = d;
      window_clip(d, reg[12] & 1);
      break;
    }

    default:
    {
      reg[r] = d;
      break;
    }
  }
}