/***************************************************************************************1* Genesis Plus2* Video Display Processor (68k & Z80 CPU interface)3*4* Support for SG-1000, Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP5*6* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)7* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)8*9* Redistribution and use of this code or any derivative works are permitted10* provided that the following conditions are met:11*12* - Redistributions may not be sold, nor may they be used in a commercial13* product or activity.14*15* - Redistributions that are modified from the original source must include the16* complete source code, including the source code for all components used by a17* binary built from the modified sources. However, as a special exception, the18* source code distributed need not include anything that is normally distributed19* (in either source or binary form) with the major components (compiler, kernel,20* and so on) of the operating system on which the executable runs, unless that21* component itself accompanies the executable.22*23* - Redistributions must reproduce the above copyright notice, this list of24* conditions and the following disclaimer in the documentation and/or other25* materials provided with the distribution.26*27* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"28* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE29* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE30* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE31* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR32* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF33* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS34* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN35* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)36* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE37* POSSIBILITY OF SUCH DAMAGE.38*39****************************************************************************************/4041#include "shared.h"42#include "hvc.h"43#include "../cinterface/callbacks.h"4445/* Mark a pattern as modified */46#define MARK_BG_DIRTY(addr) \47{ \48name = (addr >> 5) & 0x7FF; \49if(bg_name_dirty[name] == 0) \50{ \51bg_name_list[bg_list_index++] = name; \52} \53bg_name_dirty[name] |= (1 << ((addr >> 2) & 7)); \54}5556/* VDP context */57uint8 sat[0x400]; /* Internal copy of sprite attribute table */58uint8 vram[0x10000]; /* Video RAM (64K x 8-bit) */59uint8 cram[0x80]; /* On-chip color RAM (64 x 9-bit) */60uint8 vsram[0x80]; /* On-chip vertical scroll RAM (40 x 11-bit) */61uint8 reg[0x20]; /* Internal VDP registers (23 x 8-bit) */62uint8 hint_pending; /* 0= Line interrupt is pending */63uint8 vint_pending; /* 1= Frame interrupt is pending */64uint16 status; /* VDP status flags */65uint32 dma_length; /* DMA remaining length */6667/* Global variables */68uint16 ntab; /* Name table A base address */69uint16 ntbb; /* Name table B base address */70uint16 ntwb; /* Name table W base address */71uint16 satb; /* Sprite attribute table base address */72uint16 hscb; /* Horizontal scroll table base address */73uint8 bg_name_dirty[0x800]; /* 1= This pattern is dirty */74uint16 bg_name_list[0x800]; /* List of modified pattern indices */75uint16 bg_list_index; /* # of modified patterns in list */76uint8 hscroll_mask; /* Horizontal Scrolling line mask */77uint8 playfield_shift; /* Width of planes A, B (in bits) */78uint8 playfield_col_mask; /* Playfield column mask */79uint16 playfield_row_mask; /* Playfield row mask */80uint16 vscroll; /* Latched vertical scroll value */81uint8 odd_frame; /* 1: odd field, 0: even field */82uint8 im2_flag; /* 1= Interlace mode 2 is being used */83uint8 interlaced; /* 1: Interlaced mode 1 or 2 */84uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */85uint16 v_counter; /* Vertical counter */86uint16 vc_max; /* Vertical counter overflow value */87uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */88uint16 max_sprite_pixels; /* Max. sprites pixels per line (parsing & rendering) */89int32 fifo_write_cnt; /* VDP FIFO write count */90uint32 fifo_slots; /* VDP FIFO access slot count */91uint32 hvc_latch; /* latched HV counter */92const uint8 *hctab; /* pointer to H Counter table */9394/* Function pointers */95void (*vdp_68k_data_w)(unsigned int data);96void (*vdp_z80_data_w)(unsigned int data);97unsigned int (*vdp_68k_data_r)(void);98unsigned int (*vdp_z80_data_r)(void);99100/* Function prototypes */101static void vdp_68k_data_w_m4(unsigned int data);102static void vdp_68k_data_w_m5(unsigned int data);103static unsigned int vdp_68k_data_r_m4(void);104static unsigned int vdp_68k_data_r_m5(void);105static void vdp_z80_data_w_m4(unsigned int data);106static void vdp_z80_data_w_m5(unsigned int data);107static unsigned int vdp_z80_data_r_m4(void);108static unsigned int vdp_z80_data_r_m5(void);109static void vdp_z80_data_w_ms(unsigned int data);110static void vdp_z80_data_w_gg(unsigned int data);111static void vdp_z80_data_w_sg(unsigned int data);112static void vdp_bus_w(unsigned int data);113static void vdp_fifo_update(unsigned int cycles);114static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles);115static void vdp_dma_68k_ext(unsigned int length);116static void vdp_dma_68k_ram(unsigned int length);117static void vdp_dma_68k_io(unsigned int length);118static void vdp_dma_copy(unsigned int length);119static void vdp_dma_fill(unsigned int length);120121/* Tables that define the playfield layout */122static const uint8 hscroll_mask_table[] = { 0x00, 0x07, 0xF8, 0xFF };123static const uint8 shift_table[] = { 6, 7, 0, 8 };124static const uint8 col_mask_table[] = { 0x0F, 0x1F, 0x0F, 0x3F };125static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF };126127uint8 border; /* Border color index */128static uint8 pending; /* Pending write flag */129static uint8 code; /* Code register */130static uint8 dma_type; /* DMA mode */131static uint16 addr; /* Address register */132static uint16 addr_latch; /* Latched A15, A14 of address */133static uint16 sat_base_mask; /* Base bits of SAT */134static uint16 sat_addr_mask; /* Index bits of SAT */135static uint16 dma_src; /* DMA source address */136static uint32 dma_endCycles; /* 68k cycles to DMA end */137static int dmafill; /* DMA Fill pending flag */138static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */139static uint16 fifo[4]; /* FIFO ring-buffer */140static int fifo_idx; /* FIFO write index */141static int fifo_byte_access; /* FIFO byte access flag */142static uint32 fifo_cycles; /* FIFO next access cycle */143144/* set Z80 or 68k interrupt lines */145static void (*set_irq_line)(unsigned int level);146static void (*set_irq_line_delay)(unsigned int level);147148/* Vertical counter overflow values (see hvc.h) */149static const uint16 vc_table[4][2] =150{151/* NTSC, PAL */152{0xDA , 0xF2}, /* Mode 4 (192 lines) */153{0xEA , 0x102}, /* Mode 5 (224 lines) */154{0xDA , 0xF2}, /* Mode 4 (192 lines) */155{0x106, 0x10A} /* Mode 5 (240 lines) */156};157158/* DMA Timings (number of access slots per line) */159static const uint8 dma_timing[2][2] =160{161/* H32, H40 */162{16 , 18}, /* active display */163{167, 205} /* blank display */164};165166/* DMA processing functions (set by VDP register 23 high nibble) */167static void (*const dma_func[16])(unsigned int length) =168{169/* 0x0-0x3 : DMA from 68k bus $000000-$7FFFFF (external area) */170vdp_dma_68k_ext,vdp_dma_68k_ext,vdp_dma_68k_ext,vdp_dma_68k_ext,171172/* 0x4-0x7 : DMA from 68k bus $800000-$FFFFFF (internal RAM & I/O) */173vdp_dma_68k_ram, vdp_dma_68k_io,vdp_dma_68k_ram,vdp_dma_68k_ram,174175/* 0x8-0xB : DMA Fill */176vdp_dma_fill,vdp_dma_fill,vdp_dma_fill,vdp_dma_fill,177178/* 0xC-0xF : DMA Copy */179vdp_dma_copy,vdp_dma_copy,vdp_dma_copy,vdp_dma_copy180};181182183void write_vram_byte(int addr, uint8 val)184{185uint8 *p;186addr &= 0xffff;187p = &vram[addr];188if (*p != val)189{190int name;191*p = val;192MARK_BG_DIRTY(addr);193}194}195196void flush_vram_cache(void)197{198if (bg_list_index)199{200update_bg_pattern_cache(bg_list_index);201bg_list_index = 0;202}203}204205/*--------------------------------------------------------------------------*/206/* Init, reset, context functions */207/*--------------------------------------------------------------------------*/208209void vdp_init(void)210{211/* PAL/NTSC timings */212lines_per_frame = vdp_pal ? 313: 262;213214/* CPU interrupt line(s)*/215if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)216{217/* 68k cpu */218set_irq_line = m68k_set_irq;219set_irq_line_delay = m68k_set_irq_delay;220}221else222{223/* Z80 cpu */224set_irq_line = z80_set_irq_line;225set_irq_line_delay = z80_set_irq_line;226}227}228229void vdp_reset(void)230{231int i;232233memset ((char *) sat, 0, sizeof (sat));234memset ((char *) vram, 0, sizeof (vram));235memset ((char *) cram, 0, sizeof (cram));236memset ((char *) vsram, 0, sizeof (vsram));237memset ((char *) reg, 0, sizeof (reg));238239addr = 0;240addr_latch = 0;241code = 0;242pending = 0;243border = 0;244hint_pending = 0;245vint_pending = 0;246dmafill = 0;247dma_src = 0;248dma_type = 0;249dma_length = 0;250dma_endCycles = 0;251odd_frame = 0;252im2_flag = 0;253interlaced = 0;254fifo_write_cnt = 0;255fifo_cycles = 0;256fifo_slots = 0;257fifo_idx = 0;258cached_write = -1;259fifo_byte_access = 1;260261ntab = 0;262ntbb = 0;263ntwb = 0;264satb = 0;265hscb = 0;266267vscroll = 0;268269hscroll_mask = 0x00;270playfield_shift = 6;271playfield_col_mask = 0x0F;272playfield_row_mask = 0x0FF;273sat_base_mask = 0xFE00;274sat_addr_mask = 0x01FF;275276/* reset pattern cache changes */277bg_list_index = 0;278memset ((char *) bg_name_dirty, 0, sizeof (bg_name_dirty));279memset ((char *) bg_name_list, 0, sizeof (bg_name_list));280281/* default HVC */282hvc_latch = 0x10000;283hctab = cycle2hc32;284vc_max = vc_table[0][vdp_pal];285v_counter = lines_per_frame - 1;286287/* default Window clipping */288window_clip(0,0);289290/* reset VDP status (FIFO empty flag is set) */291if (system_hw & SYSTEM_MD)292{293status = vdp_pal | 0x200;294}295else296{297status = 0;298}299300/* default display area */301bitmap.viewport.w = 256;302bitmap.viewport.h = 192;303bitmap.viewport.ow = 256;304bitmap.viewport.oh = 192;305306/* default sprite pixel width */307max_sprite_pixels = 256;308309/* default overscan area */310if ((system_hw == SYSTEM_GG) && !config.gg_extra)311{312/* Display area reduced to 160x144 if overscan is disabled */313bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;314bitmap.viewport.y = (config.overscan & 1) ? (24 * (vdp_pal + 1)) : -24;315}316else317{318bitmap.viewport.x = (config.overscan & 2) * 7;319bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);320}321322/* default rendering mode */323update_bg_pattern_cache = update_bg_pattern_cache_m4;324if (system_hw < SYSTEM_MD)325{326/* Mode 0 */327render_bg = render_bg_m0;328render_obj = render_obj_tms;329parse_satb = parse_satb_tms;330}331else332{333/* Mode 4 */334render_bg = render_bg_m4;335render_obj = render_obj_m4;336parse_satb = parse_satb_m4;337}338339/* default 68k bus interface (Mega Drive VDP only) */340vdp_68k_data_w = vdp_68k_data_w_m4;341vdp_68k_data_r = vdp_68k_data_r_m4;342343/* default Z80 bus interface */344switch (system_hw)345{346case SYSTEM_SG:347{348/* SG-1000 VDP (TMS99xx) */349vdp_z80_data_w = vdp_z80_data_w_sg;350vdp_z80_data_r = vdp_z80_data_r_m4;351break;352}353354case SYSTEM_GG:355{356/* Game Gear VDP */357vdp_z80_data_w = vdp_z80_data_w_gg;358vdp_z80_data_r = vdp_z80_data_r_m4;359break;360}361362case SYSTEM_MARKIII:363case SYSTEM_SMS:364case SYSTEM_SMS2:365case SYSTEM_GGMS:366{367/* Master System or Game Gear (in MS compatibility mode) VDP */368vdp_z80_data_w = vdp_z80_data_w_ms;369vdp_z80_data_r = vdp_z80_data_r_m4;370break;371}372373default:374{375/* Mega Drive VDP (in MS compatibility mode) */376vdp_z80_data_w = vdp_z80_data_w_m4;377vdp_z80_data_r = vdp_z80_data_r_m4;378break;379}380}381382/* SG-1000 specific */383if (system_hw == SYSTEM_SG)384{385/* 16k address decoding by default (Magical Kid Wiz) */386vdp_reg_w(1, 0x80, 0);387388/* no H-INT on TMS99xx */389vdp_reg_w(10, 0xFF, 0);390}391392/* Master System specific */393else if ((system_hw & SYSTEM_SMS) && (!(config.bios & 1) || !(system_bios & SYSTEM_SMS)))394{395/* force registers initialization (only if Master System BIOS is disabled or not loaded) */396vdp_reg_w(0 , 0x36, 0);397vdp_reg_w(1 , 0x80, 0);398vdp_reg_w(2 , 0xFF, 0);399vdp_reg_w(3 , 0xFF, 0);400vdp_reg_w(4 , 0xFF, 0);401vdp_reg_w(5 , 0xFF, 0);402vdp_reg_w(6 , 0xFF, 0);403vdp_reg_w(10, 0xFF, 0);404405/* Mode 4 */406render_bg = render_bg_m4;407render_obj = render_obj_m4;408parse_satb = parse_satb_m4;409}410411/* Mega Drive specific */412else if (((system_hw == SYSTEM_MD) || (system_hw == SYSTEM_MCD)) && (config.bios & 1) && !(system_bios & SYSTEM_MD))413{414/* force registers initialization (only if TMSS model is emulated and BOOT ROM is not loaded) */415vdp_reg_w(0 , 0x04, 0);416vdp_reg_w(1 , 0x04, 0);417vdp_reg_w(10, 0xFF, 0);418vdp_reg_w(12, 0x81, 0);419vdp_reg_w(15, 0x02, 0);420}421422/* reset color palette */423for(i = 0; i < 0x20; i ++)424{425color_update_m4(i, 0x00);426}427color_update_m4(0x40, 0x00);428}429430int vdp_context_save(uint8 *state)431{432int bufferptr = 0;433434save_param(sat, sizeof(sat));435save_param(vram, sizeof(vram));436save_param(cram, sizeof(cram));437save_param(vsram, sizeof(vsram));438save_param(reg, sizeof(reg));439save_param(&addr, sizeof(addr));440save_param(&addr_latch, sizeof(addr_latch));441save_param(&code, sizeof(code));442save_param(&pending, sizeof(pending));443save_param(&status, sizeof(status));444save_param(&dmafill, sizeof(dmafill));445save_param(&fifo_idx, sizeof(fifo_idx));446save_param(&fifo, sizeof(fifo));447save_param(&hint_pending, sizeof(hint_pending));448save_param(&vint_pending, sizeof(vint_pending));449save_param(&dma_length, sizeof(dma_length));450save_param(&dma_type, sizeof(dma_type));451save_param(&dma_src, sizeof(dma_src));452save_param(&cached_write, sizeof(cached_write));453return bufferptr;454}455456int vdp_context_load(uint8 *state, uint8 version)457{458int i, bufferptr = 0;459uint8 temp_reg[0x20];460461load_param(sat, sizeof(sat));462load_param(vram, sizeof(vram));463load_param(cram, sizeof(cram));464load_param(vsram, sizeof(vsram));465load_param(temp_reg, sizeof(temp_reg));466467/* restore VDP registers */468if (system_hw < SYSTEM_MD)469{470if (system_hw > SYSTEM_SG)471{472for (i=0;i<0x10;i++)473{474pending = 1;475addr_latch = temp_reg[i];476vdp_sms_ctrl_w(0x80 | i);477}478}479else480{481for (i=0;i<0x08;i++)482{483pending = 1;484addr_latch = temp_reg[i];485vdp_tms_ctrl_w(0x80 | i);486}487}488}489else490{491for (i=0;i<0x20;i++)492{493vdp_reg_w(i, temp_reg[i], 0);494}495}496497load_param(&addr, sizeof(addr));498load_param(&addr_latch, sizeof(addr_latch));499load_param(&code, sizeof(code));500load_param(&pending, sizeof(pending));501load_param(&status, sizeof(status));502503/* 1.7.1 state compatibility */504if (version < 0x35)505{506uint16 temp;507load_param(&temp, 2);508dmafill = temp >> 8;509temp &= 0xff;510fifo_idx = 0;511fifo[0] = fifo[1] = fifo[2] = fifo[3] = (temp << 8) | temp;512}513else514{515load_param(&dmafill, sizeof(dmafill));516load_param(&fifo_idx, sizeof(fifo_idx));517load_param(&fifo, sizeof(fifo));518}519520load_param(&hint_pending, sizeof(hint_pending));521load_param(&vint_pending, sizeof(vint_pending));522load_param(&dma_length, sizeof(dma_length));523load_param(&dma_type, sizeof(dma_type));524load_param(&dma_src, sizeof(dma_src));525load_param(&cached_write, sizeof(cached_write));526527/* restore FIFO byte access flag */528fifo_byte_access = ((code & 0x0F) < 0x03);529530/* restore current NTSC/PAL mode */531if (system_hw & SYSTEM_MD)532{533status = (status & ~1) | vdp_pal;534}535536if (reg[1] & 0x04)537{538/* Mode 5 */539bg_list_index = 0x800;540541/* reinitialize palette */542color_update_m5(0, *(uint16 *)&cram[border << 1]);543for(i = 1; i < 0x40; i++)544{545color_update_m5(i, *(uint16 *)&cram[i << 1]);546}547}548else549{550/* Modes 0,1,2,3,4 */551bg_list_index = 0x200;552553/* reinitialize palette */554for(i = 0; i < 0x20; i ++)555{556color_update_m4(i, *(uint16 *)&cram[i << 1]);557}558color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);559}560561/* invalidate cache */562for (i=0;i<bg_list_index;i++)563{564bg_name_list[i]=i;565bg_name_dirty[i]=0xFF;566}567568return bufferptr;569}570571572/*--------------------------------------------------------------------------*/573/* DMA update function (Mega Drive VDP only) */574/*--------------------------------------------------------------------------*/575576void vdp_dma_update(unsigned int cycles)577{578int dma_cycles, dma_bytes;579580/* DMA transfer rate (bytes per line)581582According to the manual, here's a table that describes the transfer583rates of each of the three DMA types:584585DMA Mode Width Display Transfer Count586-----------------------------------------------------58768K > VDP 32-cell Active 16588Blanking 16758940-cell Active 18590Blanking 205591VRAM Fill 32-cell Active 15592Blanking 16659340-cell Active 17594Blanking 204595VRAM Copy 32-cell Active 8596Blanking 8359740-cell Active 9598Blanking 102599600'Active' is the active display period, 'Blanking' is either the vertical601blanking period or when the display is forcibly blanked via register #1.602603The above transfer counts are all in bytes, unless the destination is604CRAM or VSRAM for a 68K > VDP transfer, in which case it is in words.605*/606unsigned int rate = dma_timing[(status & 8) || !(reg[1] & 0x40)][reg[12] & 1];607608/* Adjust for 68k bus DMA to VRAM (one word = 2 access) or DMA Copy (one read + one write = 2 access) */609rate = rate >> (dma_type & 1);610611/* Remaining DMA cycles */612if (status & 8)613{614/* Process DMA until the end of VBLANK */615/* NOTE: DMA timings can not change during VBLANK because active display width cannot be modified. */616/* Indeed, writing VDP registers during DMA is either impossible (when doing DMA from 68k bus, CPU */617/* is locked) or will abort DMA operation (in case of DMA Fill or Copy). */618dma_cycles = (lines_per_frame * MCYCLES_PER_LINE) - cycles;619}620else621{622/* Process DMA until the end of current line */623dma_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - cycles;624}625626/* Remaining DMA bytes for that line */627dma_bytes = (dma_cycles * rate) / MCYCLES_PER_LINE;628629#ifdef LOGVDP630error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)(%d cycles left)-> %d access (%d remaining) (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE,dma_type, rate, dma_cycles, dma_bytes, dma_length, m68k_get_reg(M68K_REG_PC));631#endif632633/* Check if DMA can be finished before the end of current line */634if (dma_length < dma_bytes)635{636/* Adjust remaining DMA bytes */637dma_bytes = dma_length;638dma_cycles = (dma_bytes * MCYCLES_PER_LINE) / rate;639}640641/* Update DMA timings */642if (dma_type < 2)643{644/* 68K is frozen during DMA from 68k bus */645m68k.cycles = cycles + dma_cycles;646#ifdef LOGVDP647error("-->CPU frozen for %d cycles\n", dma_cycles);648#endif649}650else651{652/* Set DMA Busy flag */653status |= 0x02;654655/* 68K is still running, set DMA end cycle */656dma_endCycles = cycles + dma_cycles;657#ifdef LOGVDP658error("-->DMA ends in %d cycles\n", dma_cycles);659#endif660}661662/* Process DMA */663if (dma_bytes > 0)664{665/* Update DMA length */666dma_length -= dma_bytes;667668/* Process DMA operation */669dma_func[reg[23] >> 4](dma_bytes);670671/* Check if DMA is finished */672if (!dma_length)673{674/* DMA source address registers are incremented during DMA (even DMA Fill) */675uint16 end = reg[21] + (reg[22] << 8) + reg[19] + (reg[20] << 8);676reg[21] = end & 0xff;677reg[22] = end >> 8;678679/* DMA length registers are decremented during DMA */680reg[19] = reg[20] = 0;681682/* perform cached write, if any */683if (cached_write >= 0)684{685vdp_68k_ctrl_w(cached_write);686cached_write = -1;687}688}689}690}691692693/*--------------------------------------------------------------------------*/694/* Control port access functions */695/*--------------------------------------------------------------------------*/696697void vdp_68k_ctrl_w(unsigned int data)698{699/* Check pending flag */700if (pending == 0)701{702/* A single long word write instruction could have started DMA with the first word */703if (dma_length)704{705/* 68k is frozen during 68k bus DMA */706/* Second word should be written after DMA completion */707/* See Formula One & Kawasaki Superbike Challenge */708if (dma_type < 2)709{710/* Latch second control word for later */711cached_write = data;712return;713}714}715716/* Check CD0-CD1 bits */717if ((data & 0xC000) == 0x8000)718{719/* VDP register write */720vdp_reg_w((data >> 8) & 0x1F, data & 0xFF, m68k.cycles);721}722else723{724/* Set pending flag (Mode 5 only) */725pending = reg[1] & 4;726}727728/* Update address and code registers */729addr = addr_latch | (data & 0x3FFF);730code = ((code & 0x3C) | ((data >> 14) & 0x03));731}732else733{734/* Clear pending flag */735pending = 0;736737/* Save address bits A15 and A14 */738addr_latch = (data & 3) << 14;739740/* Update address and code registers */741addr = addr_latch | (addr & 0x3FFF);742code = ((code & 0x03) | ((data >> 2) & 0x3C));743744/* Detect DMA operation (CD5 bit set) */745if (code & 0x20)746{747/* DMA must be enabled */748if (reg[1] & 0x10)749{750/* DMA type */751switch (reg[23] >> 6)752{753case 2:754{755/* DMA Fill */756dma_type = 2;757758/* DMA is pending until next DATA port write */759dmafill = 1;760761/* Set DMA Busy flag */762status |= 0x02;763764/* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */765dma_endCycles = 0xffffffff;766break;767}768769case 3:770{771/* DMA Copy */772dma_type = 3;773774/* DMA length */775dma_length = (reg[20] << 8) | reg[19];776777/* Zero DMA length (pre-decrementing counter) */778if (!dma_length)779{780dma_length = 0x10000;781}782783/* DMA source address */784dma_src = (reg[22] << 8) | reg[21];785786/* Trigger DMA */787vdp_dma_update(m68k.cycles);788break;789}790791default:792{793/* DMA from 68k bus */794dma_type = (code & 0x06) ? 0 : 1;795796/* DMA length */797dma_length = (reg[20] << 8) | reg[19];798799/* Zero DMA length (pre-decrementing counter) */800if (!dma_length)801{802dma_length = 0x10000;803}804805/* DMA source address */806dma_src = (reg[22] << 8) | reg[21];807808/* Transfer from SVP ROM/RAM ($000000-$3fffff) or CD Word-RAM ($200000-$3fffff/$600000-$7fffff) */809if (((system_hw == SYSTEM_MCD) && ((reg[23] & 0x70) == ((scd.cartridge.boot >> 1) + 0x10))) || (svp && !(reg[23] & 0x60)))810{811/* source data is available with one cycle delay, i.e first word written by VDP is */812/* previous data being held on 68k bus at that time, then source words are written */813/* normally to VDP RAM, with only last source word being ignored */814addr += reg[15];815dma_length--;816}817818/* Trigger DMA */819vdp_dma_update(m68k.cycles);820break;821}822}823}824}825}826827/*828FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace)829--------------------------------------------------------------------------830Each VRAM access is byte wide, so one VRAM write (word) need two slot access.831832NOTE: Invalid code 0x02 (register write) should not behave the same as VRAM833access, i.e data is ignored and only one access slot is used for each word,834BUT a few games ("Clue", "Microcosm") which accidentally corrupt code value835will have issues when emulating FIFO timings. They likely work fine on real836hardware because of periodical 68k wait-states which have been observed and837would naturaly add some delay between writes. Until those wait-states are838accurately measured and emulated, delay is forced when invalid code value839is being used.840*/841fifo_byte_access = ((code & 0x0F) <= 0x02);842}843844/* Mega Drive VDP control port specific (MS compatibility mode) */845void vdp_z80_ctrl_w(unsigned int data)846{847switch (pending)848{849case 0:850{851/* Latch LSB */852addr_latch = data;853854/* Set LSB pending flag */855pending = 1;856return;857}858859case 1:860{861/* Update address and code registers */862addr = (addr & 0xC000) | ((data & 0x3F) << 8) | addr_latch ;863code = ((code & 0x3C) | ((data >> 6) & 0x03));864865if ((code & 0x03) == 0x02)866{867/* VDP register write */868vdp_reg_w(data & 0x1F, addr_latch, Z80.cycles);869870/* Clear pending flag */871pending = 0;872return;873}874875/* Set Mode 5 pending flag */876pending = (reg[1] & 4) >> 1;877878if (!pending && !(code & 0x03))879{880/* Process VRAM read */881fifo[0] = vram[addr & 0x3FFF];882883/* Increment address register */884addr += (reg[15] + 1);885}886return;887}888889case 2:890{891/* Latch LSB */892addr_latch = data;893894/* Set LSB pending flag */895pending = 3;896return;897}898899case 3:900{901/* Clear pending flag */902pending = 0;903904/* Update address and code registers */905addr = ((addr_latch & 3) << 14) | (addr & 0x3FFF);906code = ((code & 0x03) | ((addr_latch >> 2) & 0x3C));907908/* Detect DMA operation (CD5 bit set) */909if (code & 0x20)910{911/* DMA should be enabled */912if (reg[1] & 0x10)913{914/* DMA type */915switch (reg[23] >> 6)916{917case 2:918{919/* DMA Fill will be triggered by next write to DATA port */920dmafill = 1;921922/* Set DMA Busy flag */923status |= 0x02;924925/* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */926dma_endCycles = 0xffffffff;927break;928}929930case 3:931{932/* DMA copy */933dma_type = 3;934935/* DMA length */936dma_length = (reg[20] << 8) | reg[19];937938/* Zero DMA length (pre-decrementing counter) */939if (!dma_length)940{941dma_length = 0x10000;942}943944/* DMA source address */945dma_src = (reg[22] << 8) | reg[21];946947/* Trigger DMA */948vdp_dma_update(Z80.cycles);949break;950}951952default:953{954/* DMA from 68k bus does not work when Z80 is in control */955break;956}957}958}959}960}961return;962}963}964965/* Master System & Game Gear VDP control port specific */966void vdp_sms_ctrl_w(unsigned int data)967{968if(pending == 0)969{970/* Update address register LSB */971addr = (addr & 0x3F00) | (data & 0xFF);972973/* Latch LSB */974addr_latch = data;975976/* Set LSB pending flag */977pending = 1;978}979else980{981/* Update address and code registers */982code = (data >> 6) & 3;983addr = (data << 8 | addr_latch) & 0x3FFF;984985/* Clear pending flag */986pending = 0;987988if (code == 0)989{990/* Process VRAM read */991fifo[0] = vram[addr & 0x3FFF];992993/* Increment address register */994addr = (addr + 1) & 0x3FFF;995return;996}997998if (code == 2)999{1000/* Save current VDP mode */1001int mode, prev = (reg[0] & 0x06) | (reg[1] & 0x18);10021003/* Write VDP register 0-15 */1004vdp_reg_w(data & 0x0F, addr_latch, Z80.cycles);10051006/* Check VDP mode changes */1007mode = (reg[0] & 0x06) | (reg[1] & 0x18);1008prev ^= mode;10091010if (prev)1011{1012/* Check for extended modes */1013if (system_hw > SYSTEM_SMS)1014{1015int height;10161017if (mode == 0x0E) /* M1=0,M2=1,M3=1,M4=1 */1018{1019/* Mode 4 extended (240 lines) */1020height = 240;10211022/* Update vertical counter max value */1023vc_max = vc_table[3][vdp_pal];1024}1025else if (mode == 0x16) /* M1=1,M2=1,M3=0,M4=1 */1026{1027/* Mode 4 extended (224 lines) */1028height = 224;10291030/* Update vertical counter max value */1031vc_max = vc_table[1][vdp_pal];1032}1033else1034{1035/* Mode 4 default (224 lines) */1036height = 192;10371038/* Default vertical counter max value */1039vc_max = vc_table[0][vdp_pal];1040}10411042if (height != bitmap.viewport.h)1043{1044if (status & 8)1045{1046/* viewport changes should be applied on next frame */1047bitmap.viewport.changed |= 2;1048}1049else1050{1051/* update active display */1052bitmap.viewport.h = height;10531054/* update vertical overscan */1055if (config.overscan & 1)1056{1057bitmap.viewport.y = (240 + 48*vdp_pal - height) >> 1;1058}1059else1060{1061if ((system_hw == SYSTEM_GG) && !config.gg_extra)1062{1063/* Display area reduced to 160x144 */1064bitmap.viewport.y = (144 - height) / 2;1065}1066else1067{1068bitmap.viewport.y = 0;1069}1070}1071}1072}1073}10741075/* Rendering mode */1076switch (mode)1077{1078case 0x00: /* Graphics I */1079{1080render_bg = render_bg_m0;1081break;1082}10831084case 0x10: /* Text */1085{1086render_bg = render_bg_m1;1087break;1088}10891090case 0x02: /* Graphics II */1091{1092render_bg = render_bg_m2;1093break;1094}10951096case 0x12: /* Text (Extended PG) */1097{1098render_bg = render_bg_m1x;1099break;1100}11011102case 0x08: /* Multicolor */1103{1104render_bg = render_bg_m3;1105break;1106}11071108case 0x18: /* Invalid (1+3) */1109{1110render_bg = render_bg_inv;1111break;1112}11131114case 0x0A: /* Multicolor (Extended PG) */1115{1116render_bg = render_bg_m3x;1117break;1118}11191120case 0x1A: /* Invalid (1+2+3) */1121{1122render_bg = render_bg_inv;1123break;1124}11251126default: /* Mode 4 */1127{1128render_bg = render_bg_m4;1129break;1130}1131}11321133/* Mode switching */1134if (prev & 0x04)1135{1136int i;11371138if (mode & 0x04)1139{1140/* Mode 4 sprites */1141parse_satb = parse_satb_m4;1142render_obj = render_obj_m4;11431144/* force BG cache update*/1145bg_list_index = 0x200;1146}1147else1148{1149/* TMS-mode sprites */1150parse_satb = parse_satb_tms;1151render_obj = render_obj_tms;11521153/* BG cache is not used */1154bg_list_index = 0;1155}11561157/* reinitialize palette */1158for(i = 0; i < 0x20; i ++)1159{1160color_update_m4(i, *(uint16 *)&cram[i << 1]);1161}1162color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);1163}1164}1165}1166}1167}11681169/* SG-1000 VDP (TMS99xx) control port specific */1170void vdp_tms_ctrl_w(unsigned int data)1171{1172if(pending == 0)1173{1174/* Latch LSB */1175addr_latch = data;11761177/* Set LSB pending flag */1178pending = 1;1179}1180else1181{1182/* Update address and code registers */1183code = (data >> 6) & 3;1184addr = (data << 8 | addr_latch) & 0x3FFF;11851186/* Clear pending flag */1187pending = 0;11881189if (code == 0)1190{1191/* Process VRAM read */1192fifo[0] = vram[addr & 0x3FFF];11931194/* Increment address register */1195addr = (addr + 1) & 0x3FFF;1196return;1197}11981199if (code & 2)1200{1201/* VDP register index (0-7) */1202data &= 0x07;12031204/* Write VDP register */1205vdp_reg_w(data, addr_latch, Z80.cycles);12061207/* Check VDP mode changes */1208if (data < 2)1209{1210int mode = (reg[0] & 0x02) | (reg[1] & 0x18);12111212/* Rendering mode */1213switch (mode)1214{1215case 0x00: /* Graphics I */1216{1217render_bg = render_bg_m0;1218break;1219}12201221case 0x10: /* Text */1222{1223render_bg = render_bg_m1;1224break;1225}12261227case 0x02: /* Graphics II */1228{1229render_bg = render_bg_m2;1230break;1231}12321233case 0x12: /* Text (Extended PG) */1234{1235render_bg = render_bg_m1x;1236break;1237}12381239case 0x08: /* Multicolor */1240{1241render_bg = render_bg_m3;1242break;1243}12441245case 0x18: /* Invalid (1+3) */1246{1247render_bg = render_bg_inv;1248break;1249}12501251case 0x0A: /* Multicolor (Extended PG) */1252{1253render_bg = render_bg_m3x;1254break;1255}12561257case 0x1A: /* Invalid (1+2+3) */1258{1259render_bg = render_bg_inv;1260break;1261}1262}1263}1264}1265}1266}12671268/*1269* Status register1270*1271* Bits1272* 0 NTSC(0)/PAL(1)1273* 1 DMA Busy1274* 2 During HBlank1275* 3 During VBlank1276* 4 0:1 even:odd field (interlaced modes only)1277* 5 Sprite collision1278* 6 Too many sprites per line1279* 7 v interrupt occurred1280* 8 Write FIFO full1281* 9 Write FIFO empty1282* 10 - 15 Open Bus1283*/1284unsigned int vdp_68k_ctrl_r(unsigned int cycles)1285{1286unsigned int temp;12871288/* Update FIFO status flags if not empty */1289if (fifo_write_cnt)1290{1291vdp_fifo_update(cycles);1292}12931294/* Check if DMA Busy flag is set */1295if (status & 2)1296{1297/* Check if DMA is finished */1298if (!dma_length && (cycles >= dma_endCycles))1299{1300/* Clear DMA Busy flag */1301status &= 0xFFFD;1302}1303}13041305/* Return VDP status */1306temp = status;13071308/* Clear pending flag */1309pending = 0;13101311/* Clear SOVR & SCOL flags */1312status &= 0xFF9F;13131314/* Display OFF: VBLANK flag is set */1315if (!(reg[1] & 0x40))1316{1317temp |= 0x08;1318}13191320/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican, V.R Troopers, Gouketsuji Ichizoku,...) */1321/* NB: this is not 100% accurate and need to be verified on real hardware */1322if ((cycles % MCYCLES_PER_LINE) < 588)1323{1324temp |= 0x04;1325}13261327#ifdef LOGVDP1328error("[%d(%d)][%d(%d)] VDP 68k status read -> 0x%x (0x%x) (%x)\n", v_counter, cycles/MCYCLES_PER_LINE-1, cycles, cycles%MCYCLES_PER_LINE, temp, status, m68k_get_reg(M68K_REG_PC));1329#endif1330return (temp);1331}13321333unsigned int vdp_z80_ctrl_r(unsigned int cycles)1334{1335unsigned int temp;13361337/* Cycle-accurate SOVR & VINT flags */1338int line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;13391340/* Check if DMA busy flag is set (Mega Drive VDP specific) */1341if (status & 2)1342{1343/* Check if DMA is finished */1344if (!dma_length && (cycles >= dma_endCycles))1345{1346/* Clear DMA Busy flag */1347status &= 0xFD;1348}1349}13501351/* Check if we are already on next line */1352if (line > v_counter)1353{1354v_counter = line;1355if (line == (bitmap.viewport.h + 1))1356{1357/* set VINT flag (immediately cleared after) */1358status |= 0x80;1359}1360else if ((line >= 0) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))1361{1362/* render next line to check sprites overflow & collision */1363render_line(line);1364}1365}13661367/* Return VDP status */1368temp = status;13691370/* Clear pending flag */1371pending = 0;13721373/* Clear VINT, SOVR & SCOL flags */1374status &= 0xFF1F;13751376/* Mega Drive VDP specific */1377if (system_hw & SYSTEM_MD)1378{1379/* Display OFF: VBLANK flag is set */1380if (!(reg[1] & 0x40))1381{1382temp |= 0x08;1383}13841385/* HBLANK flag */1386if ((cycles % MCYCLES_PER_LINE) < 588)1387{1388temp |= 0x04;1389}1390}1391else if (reg[0] & 0x04)1392{1393/* Mode 4 unused bits (fixes PGA Tour Golf) */1394temp |= 0x1F;1395}13961397/* Cycle-accurate SCOL flag */1398if ((temp & 0x20) && (line == (spr_col >> 8)))1399{1400if (system_hw & SYSTEM_MD)1401{1402/* COL flag is set at HCount 0xFF on MD */1403if ((cycles % MCYCLES_PER_LINE) < 105)1404{1405status |= 0x20;1406temp &= ~0x20;1407}1408}1409else1410{1411/* COL flag is set at the pixel it occurs */1412uint8 hc = hctab[(cycles + SMS_CYCLE_OFFSET + 15) % MCYCLES_PER_LINE];1413if ((hc < (spr_col & 0xff)) || (hc > 0xf3))1414{1415status |= 0x20;1416temp &= ~0x20;1417}1418}1419}14201421/* Clear HINT & VINT pending flags */1422hint_pending = vint_pending = 0;14231424/* Clear Z80 interrupt */1425Z80.irq_state = CLEAR_LINE;14261427#ifdef LOGVDP1428error("[%d(%d)][%d(%d)] VDP Z80 status read -> 0x%x (0x%x) (%x)\n", v_counter, cycles/MCYCLES_PER_LINE-1, cycles, cycles%MCYCLES_PER_LINE, temp, status, Z80.pc.w.l);1429#endif1430return (temp);1431}14321433/*--------------------------------------------------------------------------*/1434/* HV Counters */1435/*--------------------------------------------------------------------------*/14361437unsigned int vdp_hvc_r(unsigned int cycles)1438{1439int vc;1440unsigned int data = hvc_latch;14411442/* Check if HVC latch is enabled */1443if (data)1444{1445/* Mode 5: HV-counters are frozen (cf. lightgun games, Sunset Riders logo) */1446if (reg[1] & 0x04)1447{1448#ifdef LOGVDP1449error("[%d(%d)][%d(%d)] HVC latch read -> 0x%x (%x)\n", v_counter, (cycles/MCYCLES_PER_LINE-1)%lines_per_frame, cycles, cycles%MCYCLES_PER_LINE, data & 0xffff, m68k_get_reg(M68K_REG_PC));1450#endif1451/* return latched HVC value */1452return (data & 0xffff);1453}1454else1455{1456/* Mode 4: by default, V-counter runs normally & H counter is frozen */1457data &= 0xff;1458}1459}1460else1461{1462/* Cycle-accurate H-Counter (Striker, Mickey Mania, Skitchin, Road Rash I,II,III, Sonic 3D Blast...) */1463data = hctab[cycles % MCYCLES_PER_LINE];1464}14651466/* Cycle-accurate V-Counter (cycle counter starts from line -1) */1467vc = (cycles / MCYCLES_PER_LINE) - 1;14681469/* V-Counter overflow */1470if (vc > vc_max)1471{1472vc -= lines_per_frame;1473}14741475/* Interlaced modes */1476if (interlaced)1477{1478/* Interlace mode 2 (Sonic the Hedgehog 2, Combat Cars) */1479vc <<= im2_flag;14801481/* Replace bit 0 with bit 8 */1482vc = (vc & ~1) | ((vc >> 8) & 1);1483}14841485/* return H-Counter in LSB & V-Counter in MSB */1486data |= ((vc & 0xff) << 8);14871488#ifdef LOGVDP1489error("[%d(%d)][%d(%d)] HVC read -> 0x%x (%x)\n", v_counter, (cycles/MCYCLES_PER_LINE-1)%lines_per_frame, cycles, cycles%MCYCLES_PER_LINE, data, m68k_get_reg(M68K_REG_PC));1490#endif1491return (data);1492}149314941495/*--------------------------------------------------------------------------*/1496/* Test registers */1497/*--------------------------------------------------------------------------*/14981499void vdp_test_w(unsigned int data)1500{1501#ifdef LOGERROR1502error("Unused VDP Write 0x%x (%08x)\n", data, m68k_get_reg(M68K_REG_PC));1503#endif1504}150515061507/*--------------------------------------------------------------------------*/1508/* 68k interrupt handler (TODO: check how interrupts are handled in Mode 4) */1509/*--------------------------------------------------------------------------*/15101511int vdp_68k_irq_ack(int int_level)1512{1513#ifdef LOGVDP1514error("[%d(%d)][%d(%d)] INT Level %d ack (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE,int_level, m68k_get_reg(M68K_REG_PC));1515#endif15161517/* VINT has higher priority (Fatal Rewind) */1518if (vint_pending & reg[1])1519{1520#ifdef LOGVDP1521error("---> VINT cleared\n");1522#endif15231524/* Clear VINT pending flag */1525vint_pending = 0;1526status &= ~0x80;15271528/* Update IRQ status */1529if (hint_pending & reg[0])1530{1531m68k_set_irq(4);1532}1533else1534{1535m68k_set_irq(0);1536}1537}1538else1539{1540#ifdef LOGVDP1541error("---> HINT cleared\n");1542#endif15431544/* Clear HINT pending flag */1545hint_pending = 0;15461547/* Update IRQ status */1548m68k_set_irq(0);1549}15501551return M68K_INT_ACK_AUTOVECTOR;1552}155315541555/*--------------------------------------------------------------------------*/1556/* VDP registers update function */1557/*--------------------------------------------------------------------------*/15581559static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles)1560{1561#ifdef LOGVDP1562error("[%d(%d)][%d(%d)] VDP register %d write -> 0x%x (%x)\n", v_counter, cycles/MCYCLES_PER_LINE-1, cycles, cycles%MCYCLES_PER_LINE, r, d, m68k_get_reg(M68K_REG_PC));1563#endif15641565/* VDP registers #11 to #23 cannot be updated in Mode 4 (Captain Planet & Avengers, Bass Master Classic Pro Edition) */1566if (!(reg[1] & 4) && (r > 10))1567{1568return;1569}15701571switch(r)1572{1573case 0: /* CTRL #1 */1574{1575/* Look for changed bits */1576r = d ^ reg[0];1577reg[0] = d;15781579/* Line Interrupt */1580if ((r & 0x10) && hint_pending)1581{1582/* Update IRQ status */1583if (vint_pending & reg[1])1584{1585set_irq_line(6);1586}1587else if (d & 0x10)1588{1589set_irq_line_delay(4);1590}1591else1592{1593set_irq_line(0);1594}1595}15961597/* Palette selection */1598if (r & 0x04)1599{1600/* Mega Drive VDP only */1601if (system_hw & SYSTEM_MD)1602{1603/* Reset color palette */1604int i;1605if (reg[1] & 0x04)1606{1607/* Mode 5 */1608color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1609for (i = 1; i < 0x40; i++)1610{1611color_update_m5(i, *(uint16 *)&cram[i << 1]);1612}1613}1614else1615{1616/* Mode 4 */1617for (i = 0; i < 0x20; i++)1618{1619color_update_m4(i, *(uint16 *)&cram[i << 1]);1620}1621color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);1622}1623}1624}16251626/* HVC latch (Sunset Riders, Lightgun games) */1627if (r & 0x02)1628{1629/* Mega Drive VDP only */1630if (system_hw & SYSTEM_MD)1631{1632/* Mode 5 only */1633if (reg[1] & 0x04)1634{1635if (d & 0x02)1636{1637/* Latch current HVC */1638hvc_latch = vdp_hvc_r(cycles) | 0x10000;1639}1640else1641{1642/* Free-running HVC */1643hvc_latch = 0;1644}1645}1646}1647}1648break;1649}16501651case 1: /* CTRL #2 */1652{1653/* Look for changed bits */1654r = d ^ reg[1];1655reg[1] = d;16561657/* Display status (modified during active display) */1658if ((r & 0x40) && (v_counter < bitmap.viewport.h))1659{1660/* Cycle offset vs HBLANK */1661int offset = cycles - mcycles_vdp;1662if (offset <= 860)1663{1664/* Sprite rendering is limited if display was disabled during HBLANK (Mickey Mania 3d level, Overdrive Demo) */1665if (d & 0x40)1666{1667/* NB: This is not 100% accurate. On real hardware, the maximal number of rendered sprites pixels */1668/* for the current line (normally 256 or 320 pixels) but also the maximal number of pre-processed */1669/* sprites for the next line (normally 64 or 80 sprites) are both reduced depending on the amount */1670/* of cycles spent with display disabled. Here we only reduce them by a fixed amount when display */1671/* has been reenabled after a specific point within HBLANK. */1672if (offset > 360)1673{1674max_sprite_pixels = 128;1675}1676}16771678/* Redraw entire line (Legend of Galahad, Lemmings 2, Formula One, Kawasaki Super Bike, Deadly Moves,...) */1679render_line(v_counter);16801681/* Restore default */1682max_sprite_pixels = 256 + ((reg[12] & 1) << 6);1683}1684else if (system_hw & SYSTEM_MD)1685{1686/* Active pixel offset */1687if (reg[12] & 1)1688{1689/* dot clock = MCLK / 8 */1690offset = ((offset - 860) / 8) + 16;1691}1692else1693{1694/* dot clock = MCLK / 10 */1695offset = ((offset - 860) / 10) + 16;1696}16971698/* Line is partially blanked (Nigel Mansell's World Championship Racing , Ren & Stimpy Show, ...) */1699if (offset < bitmap.viewport.w)1700{1701if (d & 0x40)1702{1703render_line(v_counter);1704blank_line(v_counter, 0, offset);1705}1706else1707{1708blank_line(v_counter, offset, bitmap.viewport.w - offset);1709}1710}1711}1712}17131714/* Frame Interrupt */1715if ((r & 0x20) && vint_pending)1716{1717/* Update IRQ status */1718if (d & 0x20)1719{1720set_irq_line_delay(6);1721}1722else if (hint_pending & reg[0])1723{1724set_irq_line(4);1725}1726else1727{1728set_irq_line(0);1729}1730}17311732/* Active display height */1733if (r & 0x08)1734{1735/* Mega Drive VDP only */1736if (system_hw & SYSTEM_MD)1737{1738/* Mode 5 only */1739if (d & 0x04)1740{1741/* Changes should be applied on next frame */1742bitmap.viewport.changed |= 2;17431744/* Update vertical counter max value */1745vc_max = vc_table[(d >> 2) & 3][vdp_pal];1746}1747}1748}17491750/* Rendering mode */1751if (r & 0x04)1752{1753/* Mega Drive VDP only */1754if (system_hw & SYSTEM_MD)1755{1756int i;1757if (d & 0x04)1758{1759/* Mode 5 rendering */1760parse_satb = parse_satb_m5;1761update_bg_pattern_cache = update_bg_pattern_cache_m5;1762if (im2_flag)1763{1764render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;1765render_obj = (reg[12] & 0x08) ? render_obj_m5_im2_ste : render_obj_m5_im2;1766}1767else1768{1769render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;1770render_obj = (reg[12] & 0x08) ? render_obj_m5_ste : render_obj_m5;1771}17721773/* Reset color palette */1774color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1775for (i = 1; i < 0x40; i++)1776{1777color_update_m5(i, *(uint16 *)&cram[i << 1]);1778}17791780/* Mode 5 bus access */1781vdp_68k_data_w = vdp_68k_data_w_m5;1782vdp_z80_data_w = vdp_z80_data_w_m5;1783vdp_68k_data_r = vdp_68k_data_r_m5;1784vdp_z80_data_r = vdp_z80_data_r_m5;17851786/* Change display height */1787if (status & 8)1788{1789/* viewport changes should be applied on next frame */1790bitmap.viewport.changed |= 2;1791}1792else1793{1794/* Update current frame active display height */1795bitmap.viewport.h = 224 + ((d & 8) << 1);1796bitmap.viewport.y = (config.overscan & 1) * (8 - (d & 8) + 24*vdp_pal);1797}17981799/* Clear HVC latched value */1800hvc_latch = 0;18011802/* Check if HVC latch bit is set */1803if (reg[0] & 0x02)1804{1805/* Latch current HVC */1806hvc_latch = vdp_hvc_r(cycles) | 0x10000;1807}18081809/* max tiles to invalidate */1810bg_list_index = 0x800;1811}1812else1813{1814/* Mode 4 rendering */1815parse_satb = parse_satb_m4;1816update_bg_pattern_cache = update_bg_pattern_cache_m4;1817render_bg = render_bg_m4;1818render_obj = render_obj_m4;18191820/* Reset color palette */1821for (i = 0; i < 0x20; i++)1822{1823color_update_m4(i, *(uint16 *)&cram[i << 1]);1824}1825color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);18261827/* Mode 4 bus access */1828vdp_68k_data_w = vdp_68k_data_w_m4;1829vdp_z80_data_w = vdp_z80_data_w_m4;1830vdp_68k_data_r = vdp_68k_data_r_m4;1831vdp_z80_data_r = vdp_z80_data_r_m4;18321833if (status & 8)1834{1835/* viewport changes should be applied on next frame */1836bitmap.viewport.changed |= 2;1837}1838else1839{1840/* Update current frame active display */1841bitmap.viewport.h = 192;1842bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);1843}18441845/* Latch current HVC */1846hvc_latch = vdp_hvc_r(cycles) | 0x10000;18471848/* max tiles to invalidate */1849bg_list_index = 0x200;1850}18511852/* Invalidate pattern cache */1853for (i=0;i<bg_list_index;i++)1854{1855bg_name_list[i] = i;1856bg_name_dirty[i] = 0xFF;1857}18581859/* Update vertical counter max value */1860vc_max = vc_table[(d >> 2) & 3][vdp_pal];1861}1862else1863{1864/* No effect (cleared to avoid mode 5 detection elsewhere) */1865reg[1] &= ~0x04;1866}1867}1868break;1869}18701871case 2: /* Plane A Name Table Base */1872{1873reg[2] = d;1874ntab = (d << 10) & 0xE000;18751876/* Plane A Name Table Base changed during HBLANK */1877if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1878{1879/* render entire line */1880render_line(v_counter);1881}1882break;1883}18841885case 3: /* Window Plane Name Table Base */1886{1887reg[3] = d;1888if (reg[12] & 0x01)1889{1890ntwb = (d << 10) & 0xF000;1891}1892else1893{1894ntwb = (d << 10) & 0xF800;1895}18961897/* Window Plane Name Table Base changed during HBLANK */1898if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1899{1900/* render entire line */1901render_line(v_counter);1902}1903break;1904}19051906case 4: /* Plane B Name Table Base */1907{1908reg[4] = d;1909ntbb = (d << 13) & 0xE000;19101911/* Plane B Name Table Base changed during HBLANK (Adventures of Batman & Robin) */1912if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1913{1914/* render entire line */1915render_line(v_counter);1916}19171918break;1919}19201921case 5: /* Sprite Attribute Table Base */1922{1923reg[5] = d;1924satb = (d << 9) & sat_base_mask;1925break;1926}19271928case 7: /* Backdrop color */1929{1930reg[7] = d;19311932/* Check if backdrop color changed */1933d &= 0x3F;19341935if (d != border)1936{1937/* Update backdrop color */1938border = d;19391940/* Reset palette entry */1941if (reg[1] & 4)1942{1943/* Mode 5 */1944color_update_m5(0x00, *(uint16 *)&cram[d << 1]);1945}1946else1947{1948/* Mode 4 */1949color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (d & 0x0F)) << 1]);1950}19511952/* Backdrop color modified during HBLANK (Road Rash 1,2,3)*/1953if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))1954{1955/* remap entire line */1956remap_line(v_counter);1957}1958}1959break;1960}19611962case 8: /* Horizontal Scroll (Mode 4 only) */1963{1964int line;19651966/* Hscroll is latched at HCount 0xF3, HCount 0xF6 on MD */1967/* Line starts at HCount 0xF4, HCount 0xF6 on MD */1968if (system_hw < SYSTEM_MD)1969{1970cycles = cycles + 15;1971}19721973/* Make sure Hscroll has not already been latched */1974line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;1975if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))1976{1977v_counter = line;1978render_line(line);1979}19801981reg[8] = d;1982break;1983}19841985case 11: /* CTRL #3 */1986{1987reg[11] = d;19881989/* Horizontal scrolling mode */1990hscroll_mask = hscroll_mask_table[d & 0x03];19911992/* Vertical Scrolling mode */1993if (d & 0x04)1994{1995render_bg = im2_flag ? render_bg_m5_im2_vs : render_bg_m5_vs;1996}1997else1998{1999render_bg = im2_flag ? render_bg_m5_im2 : render_bg_m5;2000}2001break;2002}20032004case 12: /* CTRL #4 */2005{2006/* Look for changed bits */2007r = d ^ reg[12];2008reg[12] = d;20092010/* Shadow & Highlight mode */2011if (r & 0x08)2012{2013/* Reset color palette */2014int i;2015color_update_m5(0x00, *(uint16 *)&cram[border << 1]);2016for (i = 1; i < 0x40; i++)2017{2018color_update_m5(i, *(uint16 *)&cram[i << 1]);2019}20202021/* Update sprite rendering function */2022if (d & 0x08)2023{2024render_obj = im2_flag ? render_obj_m5_im2_ste : render_obj_m5_ste;2025}2026else2027{2028render_obj = im2_flag ? render_obj_m5_im2 : render_obj_m5;2029}2030}20312032/* Interlaced modes */2033if (r & 0x06)2034{2035/* changes should be applied on next frame */2036bitmap.viewport.changed |= 2;2037}20382039/* Active display width */2040if (r & 0x01)2041{2042if (d & 0x01)2043{2044/* Update display-dependant registers */2045ntwb = (reg[3] << 10) & 0xF000;2046satb = (reg[5] << 9) & 0xFC00;2047sat_base_mask = 0xFC00;2048sat_addr_mask = 0x03FF;20492050/* Update HC table */2051hctab = cycle2hc40;20522053/* Update clipping */2054window_clip(reg[17], 1);20552056/* Max. sprite pixels per line */2057max_sprite_pixels = 320;2058}2059else2060{2061/* Update display-dependant registers */2062ntwb = (reg[3] << 10) & 0xF800;2063satb = (reg[5] << 9) & 0xFE00;2064sat_base_mask = 0xFE00;2065sat_addr_mask = 0x01FF;20662067/* Update HC table */2068hctab = cycle2hc32;20692070/* Update clipping */2071window_clip(reg[17], 0);20722073/* Max. sprite pixels per line */2074max_sprite_pixels = 256;2075}20762077/* Active display width modified during HBLANK (Bugs Bunny Double Trouble) */2078if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))2079{2080/* Update active display width */2081bitmap.viewport.w = 256 + ((d & 1) << 6);20822083/* Redraw entire line */2084render_line(v_counter);2085}2086else if (v_counter == (lines_per_frame - 1))2087{2088/* Update starting frame active display width */2089bitmap.viewport.w = 256 + ((d & 1) << 6);2090}2091else2092{2093/* Changes should be applied on next frame (Golden Axe III intro) */2094/* NB: not 100% accurate but required since backend framebuffer width cannot be modified mid-frame. */2095/* This would require a fixed framebuffer width (based on TV screen aspect ratio) and pixel scaling */2096/* to be done during rendering (depending on active display pixel aspect ratio in H32 or H40 mode). */2097/* Display is generally disabled when this is modified so it shouldn't be really noticeable anyway. */2098bitmap.viewport.changed |= 2;2099}2100}2101break;2102}21032104case 13: /* HScroll Base Address */2105{2106reg[13] = d;2107hscb = (d << 10) & 0xFC00;2108break;2109}21102111case 16: /* Playfield size */2112{2113reg[16] = d;2114playfield_shift = shift_table[(d & 3)];2115playfield_col_mask = col_mask_table[(d & 3)];2116playfield_row_mask = row_mask_table[(d >> 4) & 3];2117break;2118}21192120case 17: /* Window/Plane A vertical clipping */2121{2122reg[17] = d;2123window_clip(d, reg[12] & 1);2124break;2125}21262127default:2128{2129reg[r] = d;2130break;2131}2132}2133}21342135/*--------------------------------------------------------------------------*/2136/* FIFO emulation (Mega Drive VDP specific) */2137/* ---------------------------------------- */2138/* */2139/* CPU access to VRAM, CRAM & VSRAM is limited during active display: */2140/* H32 mode -> 16 access per line */2141/* H40 mode -> 18 access per line */2142/* */2143/* with fixed access slots timings detailled below. */2144/* */2145/* Each VRAM access is byte wide, so one VRAM write (word) need two slots. */2146/* */2147/*--------------------------------------------------------------------------*/21482149static void vdp_fifo_update(unsigned int cycles)2150{2151int slots, count = 0;21522153const int *fifo_timing;21542155const int fifo_cycles_h32[16+2] =2156{2157230, 510, 810, 970, 1130, 1450, 1610, 1770, 2090, 2250, 2410, 2730, 2890, 3050, 3350, 3370,2158MCYCLES_PER_LINE + 230, MCYCLES_PER_LINE + 5102159};21602161const int fifo_cycles_h40[18+2] =2162{2163352, 820, 948, 1076, 1332, 1460, 1588, 1844, 1972, 2100, 2356, 2484, 2612, 2868, 2996, 3124, 3364, 3380,2164MCYCLES_PER_LINE + 352, MCYCLES_PER_LINE + 8202165};216621672168/* number of access slots up to current line */2169if (reg[12] & 0x01)2170{2171fifo_timing = fifo_cycles_h40;2172slots = 18 * (cycles / MCYCLES_PER_LINE);2173}2174else2175{2176fifo_timing = fifo_cycles_h32;2177slots = 16 * (cycles / MCYCLES_PER_LINE);2178}21792180/* number of access slots within current line */2181cycles = cycles % MCYCLES_PER_LINE;2182while (fifo_timing[count] <= cycles)2183{2184count++;2185}21862187/* number of processed FIFO entries since last access */2188slots = (slots + count - fifo_slots) >> fifo_byte_access;21892190if (slots > 0)2191{2192/* process FIFO entries */2193fifo_write_cnt -= slots;21942195/* Clear FIFO full flag */2196status &= 0xFEFF;21972198if (fifo_write_cnt <= 0)2199{2200/* No more FIFO entries */2201fifo_write_cnt = 0;22022203/* Set FIFO empty flag */2204status |= 0x200;2205}22062207/* Update FIFO access slot counter */2208fifo_slots += (slots << fifo_byte_access);2209}22102211/* next FIFO update cycle */2212fifo_cycles = mcycles_vdp + fifo_timing[count | fifo_byte_access];2213}221422152216/*--------------------------------------------------------------------------*/2217/* Internal 16-bit data bus access function (Mode 5 only) */2218/*--------------------------------------------------------------------------*/2219static void vdp_bus_w(unsigned int data)2220{2221/* write data to next FIFO entry */2222fifo[fifo_idx] = data;22232224/* increment FIFO write pointer */2225fifo_idx = (fifo_idx + 1) & 3;22262227/* Check destination code (CD0-CD3) */2228switch (code & 0x0F)2229{2230case 0x01: /* VRAM */2231{2232/* VRAM address */2233int index = addr & 0xFFFE;22342235/* Pointer to VRAM */2236uint16 *p = (uint16 *)&vram[index];22372238/* Byte-swap data if A0 is set */2239if (addr & 1)2240{2241data = ((data >> 8) | (data << 8)) & 0xFFFF;2242}22432244/* Intercept writes to Sprite Attribute Table */2245if ((index & sat_base_mask) == satb)2246{2247/* Update internal SAT */2248*(uint16 *) &sat[index & sat_addr_mask] = data;2249}22502251/* Only write unique data to VRAM */2252if (data != *p)2253{2254int name;22552256/* Write data to VRAM */2257*p = data;22582259/* Update pattern cache */2260MARK_BG_DIRTY (index);2261}22622263#ifdef LOGVDP2264error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2265#endif2266break;2267}22682269case 0x03: /* CRAM */2270{2271/* Pointer to CRAM 9-bit word */2272uint16 *p = (uint16 *)&cram[addr & 0x7E];22732274/* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */2275data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1);22762277/* Check if CRAM data is being modified */2278if (data != *p)2279{2280/* CRAM index (64 words) */2281int index = (addr >> 1) & 0x3F;22822283/* Write CRAM data */2284*p = data;22852286/* Color entry 0 of each palette is never displayed (transparent pixel) */2287if (index & 0x0F)2288{2289/* Update color palette */2290color_update_m5(index, data);2291}22922293/* Update backdrop color */2294if (index == border)2295{2296color_update_m5(0x00, data);2297}22982299/* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */2300if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))2301{2302/* Remap current line */2303remap_line(v_counter);2304}2305}2306#ifdef LOGVDP2307error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2308#endif2309break;2310}23112312case 0x05: /* VSRAM */2313{2314*(uint16 *)&vsram[addr & 0x7E] = data;23152316/* 2-cell Vscroll mode */2317if (reg[11] & 0x04)2318{2319/* VSRAM writes during HBLANK (Adventures of Batman & Robin) */2320if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))2321{2322/* Remap current line */2323render_line(v_counter);2324}2325}2326#ifdef LOGVDP2327error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2328#endif2329break;2330}23312332default:2333{2334/* add some delay until 68k periodical wait-states are accurately emulated ("Clue", "Microcosm") */2335m68k.cycles += 2;2336#ifdef LOGERROR2337error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, data, m68k_get_reg(M68K_REG_PC));2338#endif2339break;2340}2341}23422343/* Increment address register */2344addr += reg[15];2345}234623472348/*--------------------------------------------------------------------------*/2349/* 68k bus interface (Mega Drive VDP only) */2350/*--------------------------------------------------------------------------*/23512352static void vdp_68k_data_w_m4(unsigned int data)2353{2354/* Clear pending flag */2355pending = 0;23562357/* Restricted VDP writes during active display */2358if (!(status & 8) && (reg[1] & 0x40))2359{2360/* Update VDP FIFO */2361vdp_fifo_update(m68k.cycles);23622363/* Clear FIFO empty flag */2364status &= 0xFDFF;23652366/* up to 4 words can be stored */2367if (fifo_write_cnt < 4)2368{2369/* Increment FIFO counter */2370fifo_write_cnt++;23712372/* Set FIFO full flag if 4 words are stored */2373status |= ((fifo_write_cnt & 4) << 6);2374}2375else2376{2377/* CPU is halted until next FIFO entry processing */2378m68k.cycles = fifo_cycles;23792380/* Update FIFO access slot counter */2381fifo_slots = fifo_slots + 1 + fifo_byte_access;2382}2383}23842385/* Check destination code */2386if (code & 0x02)2387{2388/* CRAM index (32 words) */2389int index = addr & 0x1F;23902391/* Pointer to CRAM 9-bit word */2392uint16 *p = (uint16 *)&cram[index << 1];23932394/* Pack 16-bit data (xxx000BBGGRR) to 9-bit CRAM data (xxxBBGGRR) */2395data = ((data & 0xE00) >> 3) | (data & 0x3F);23962397/* Check if CRAM data is being modified */2398if (data != *p)2399{2400/* Write CRAM data */2401*p = data;24022403/* Update color palette */2404color_update_m4(index, data);24052406/* Update backdrop color */2407if (index == (0x10 | (border & 0x0F)))2408{2409color_update_m4(0x40, data);2410}2411}2412}2413else2414{2415/* VRAM address (interleaved format) */2416int index = ((addr << 1) & 0x3FC) | ((addr & 0x200) >> 8) | (addr & 0x3C00);24172418/* Pointer to VRAM */2419uint16 *p = (uint16 *)&vram[index];24202421/* Byte-swap data if A0 is set */2422if (addr & 1)2423{2424data = ((data >> 8) | (data << 8)) & 0xFFFF;2425}24262427/* Only write unique data to VRAM */2428if (data != *p)2429{2430int name;24312432/* Write data to VRAM */2433*p = data;24342435/* Update the pattern cache */2436MARK_BG_DIRTY (index);2437}2438}24392440/* Increment address register (TODO: check how address is incremented in Mode 4) */2441addr += (reg[15] + 1);2442}24432444static void vdp_68k_data_w_m5(unsigned int data)2445{2446/* Clear pending flag */2447pending = 0;24482449/* Restricted VDP writes during active display */2450if (!(status & 8) && (reg[1] & 0x40))2451{2452/* Update VDP FIFO */2453vdp_fifo_update(m68k.cycles);24542455/* Clear FIFO empty flag */2456status &= 0xFDFF;24572458/* up to 4 words can be stored */2459if (fifo_write_cnt < 4)2460{2461/* Increment FIFO counter */2462fifo_write_cnt++;24632464/* Set FIFO full flag if 4 words are stored */2465status |= ((fifo_write_cnt & 4) << 6);2466}2467else2468{2469/* CPU is halted until next FIFO entry processing (Chaos Engine / Soldiers of Fortune, Double Clutch, Titan Overdrive Demo) */2470m68k.cycles = fifo_cycles;24712472/* Update FIFO access slot counter */2473fifo_slots += (1 + fifo_byte_access);2474}2475}24762477/* Write data */2478vdp_bus_w(data);24792480/* Check if DMA Fill is pending */2481if (dmafill)2482{2483/* Clear DMA Fill pending flag */2484dmafill = 0;24852486/* DMA length */2487dma_length = (reg[20] << 8) | reg[19];24882489/* Zero DMA length (pre-decrementing counter) */2490if (!dma_length)2491{2492dma_length = 0x10000;2493}24942495/* Trigger DMA */2496vdp_dma_update(m68k.cycles);2497}2498}24992500static unsigned int vdp_68k_data_r_m4(void)2501{2502/* VRAM address (interleaved format) */2503int index = ((addr << 1) & 0x3FC) | ((addr & 0x200) >> 8) | (addr & 0x3C00);25042505/* Clear pending flag */2506pending = 0;25072508/* Increment address register (TODO: check how address is incremented in Mode 4) */2509addr += (reg[15] + 1);25102511/* Read VRAM data */2512return *(uint16 *) &vram[index];2513}25142515static unsigned int vdp_68k_data_r_m5(void)2516{2517uint16 data = 0;25182519/* Clear pending flag */2520pending = 0;25212522/* Check destination code (CD0-CD3) & CD4 */2523switch (code & 0x1F)2524{2525case 0x00:2526{2527/* read two bytes from VRAM */2528data = *(uint16 *)&vram[addr & 0xFFFE];25292530#ifdef LOGVDP2531error("[%d(%d)][%d(%d)] VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2532#endif2533break;2534}25352536case 0x04:2537{2538/* VSRAM index */2539int index = addr & 0x7E;25402541/* Check against VSRAM max size (80 x 11-bits) */2542if (index >= 0x50)2543{2544/* Wrap to address 0 (TODO: check if still true with Genesis 3 model) */2545index = 0;2546}25472548/* Read 11-bit word from VSRAM */2549data = *(uint16 *)&vsram[index] & 0x7FF;25502551/* Unused bits are set using data from next available FIFO entry */2552data |= (fifo[fifo_idx] & ~0x7FF);25532554#ifdef LOGVDP2555error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2556#endif2557break;2558}25592560case 0x08:2561{2562/* Read 9-bit word from CRAM */2563data = *(uint16 *)&cram[addr & 0x7E];25642565/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit bus data (BBB0GGG0RRR0) */2566data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);25672568/* Unused bits are set using data from next available FIFO entry */2569data |= (fifo[fifo_idx] & ~0xEEE);25702571#ifdef LOGVDP2572error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2573#endif2574break;2575}25762577case 0x0c: /* undocumented 8-bit VRAM read */2578{2579/* Read one byte from VRAM adjacent address */2580data = READ_BYTE(vram, addr ^ 1);25812582/* Unused bits are set using data from next available FIFO entry */2583data |= (fifo[fifo_idx] & ~0xFF);25842585#ifdef LOGVDP2586error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));2587#endif2588break;2589}25902591default:2592{2593/* Invalid code value (normally locks VDP, hard reset required) */2594#ifdef LOGERROR2595error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x read (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, m68k_get_reg(M68K_REG_PC));2596#endif2597break;2598}2599}26002601/* Increment address register */2602addr += reg[15];26032604/* Return data */2605return data;2606}260726082609/*--------------------------------------------------------------------------*/2610/* Z80 bus interface (Mega Drive VDP in Master System compatibility mode) */2611/*--------------------------------------------------------------------------*/26122613static void vdp_z80_data_w_m4(unsigned int data)2614{2615/* Clear pending flag */2616pending = 0;26172618/* Check destination code */2619if (code & 0x02)2620{2621/* CRAM index (32 words) */2622int index = addr & 0x1F;26232624/* Pointer to CRAM word */2625uint16 *p = (uint16 *)&cram[index << 1];26262627/* Check if CRAM data is being modified */2628if (data != *p)2629{2630/* Write CRAM data */2631*p = data;26322633/* Update color palette */2634color_update_m4(index, data);26352636/* Update backdrop color */2637if (index == (0x10 | (border & 0x0F)))2638{2639color_update_m4(0x40, data);2640}2641}2642}2643else2644{2645/* VRAM address */2646int index = addr & 0x3FFF;26472648/* Only write unique data to VRAM */2649if (data != vram[index])2650{2651int name;26522653/* Write data */2654vram[index] = data;26552656/* Update pattern cache */2657MARK_BG_DIRTY(index);2658}2659}26602661/* Increment address register (TODO: check how address is incremented in Mode 4) */2662addr += (reg[15] + 1);2663}26642665static void vdp_z80_data_w_m5(unsigned int data)2666{2667/* Clear pending flag */2668pending = 0;26692670/* Push byte into FIFO */2671fifo[fifo_idx] = data << 8;2672fifo_idx = (fifo_idx + 1) & 3;26732674/* Check destination code (CD0-CD3) */2675switch (code & 0x0F)2676{2677case 0x01: /* VRAM */2678{2679/* VRAM address (write low byte to even address & high byte to odd address) */2680int index = addr ^ 1;26812682/* Intercept writes to Sprite Attribute Table */2683if ((index & sat_base_mask) == satb)2684{2685/* Update internal SAT */2686WRITE_BYTE(sat, index & sat_addr_mask, data);2687}26882689/* Only write unique data to VRAM */2690if (data != READ_BYTE(vram, index))2691{2692int name;26932694/* Write data */2695WRITE_BYTE(vram, index, data);26962697/* Update pattern cache */2698MARK_BG_DIRTY (index);2699}2700break;2701}27022703case 0x03: /* CRAM */2704{2705/* Pointer to CRAM word */2706uint16 *p = (uint16 *)&cram[addr & 0x7E];27072708/* Pack 8-bit value into 9-bit CRAM data */2709if (addr & 1)2710{2711/* Write high byte (0000BBB0 -> BBBxxxxxx) */2712data = (*p & 0x3F) | ((data & 0x0E) << 5);2713}2714else2715{2716/* Write low byte (GGG0RRR0 -> xxxGGGRRR) */2717data = (*p & 0x1C0) | ((data & 0x0E) >> 1)| ((data & 0xE0) >> 2);2718}27192720/* Check if CRAM data is being modified */2721if (data != *p)2722{2723/* CRAM index (64 words) */2724int index = (addr >> 1) & 0x3F;27252726/* Write CRAM data */2727*p = data;27282729/* Color entry 0 of each palette is never displayed (transparent pixel) */2730if (index & 0x0F)2731{2732/* Update color palette */2733color_update_m5(index, data);2734}27352736/* Update backdrop color */2737if (index == border)2738{2739color_update_m5(0x00, data);2740}2741}2742break;2743}27442745case 0x05: /* VSRAM */2746{2747/* Write low byte to even address & high byte to odd address */2748WRITE_BYTE(vsram, (addr & 0x7F) ^ 1, data);2749break;2750}2751}27522753/* Increment address register */2754addr += reg[15];27552756/* Check if DMA Fill is pending */2757if (dmafill)2758{2759/* Clear DMA Fill pending flag */2760dmafill = 0;27612762/* DMA length */2763dma_length = (reg[20] << 8) | reg[19];27642765/* Zero DMA length (pre-decrementing counter) */2766if (!dma_length)2767{2768dma_length = 0x10000;2769}27702771/* Trigger DMA */2772vdp_dma_update(Z80.cycles);2773}2774}27752776static unsigned int vdp_z80_data_r_m4(void)2777{2778/* Read buffer */2779unsigned int data = fifo[0];27802781/* Clear pending flag */2782pending = 0;27832784/* Process next read */2785fifo[0] = vram[addr & 0x3FFF];27862787/* Increment address register (TODO: check how address is incremented in Mode 4) */2788addr += (reg[15] + 1);27892790/* Return data */2791return data;2792}27932794static unsigned int vdp_z80_data_r_m5(void)2795{2796unsigned int data = 0;27972798/* Clear pending flag */2799pending = 0;28002801/* Check destination code (CD0-CD3) & CD4 */2802switch (code & 0x1F)2803{2804case 0x00: /* VRAM */2805{2806/* Return low byte from even address & high byte from odd address */2807data = READ_BYTE(vram, addr ^ 1);2808break;2809}28102811case 0x04: /* VSRAM */2812{2813/* Return low byte from even address & high byte from odd address */2814data = READ_BYTE(vsram, (addr & 0x7F) ^ 1);2815break;2816}28172818case 0x08: /* CRAM */2819{2820/* Read CRAM data */2821data = *(uint16 *)&cram[addr & 0x7E];28222823/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit data (BBB0GGG0RRR0) */2824data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);28252826/* Return low byte from even address & high byte from odd address */2827if (addr & 1)2828{2829data = data >> 8;2830}28312832data &= 0xFF;2833break;2834}2835}28362837/* Increment address register */2838addr += reg[15];28392840/* Return data */2841return data;2842}284328442845/*-----------------------------------------------------------------------------*/2846/* Z80 bus interface (Master System, Game Gear & SG-1000 VDP) */2847/*-----------------------------------------------------------------------------*/28482849static void vdp_z80_data_w_ms(unsigned int data)2850{2851/* Clear pending flag */2852pending = 0;28532854if (code < 3)2855{2856int index;28572858/* Check if we are already on next line */2859int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2860if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2861{2862/* Render next line */2863v_counter = line;2864render_line(line);2865}28662867/* VRAM address */2868index = addr & 0x3FFF;28692870/* VRAM write */2871if (data != vram[index])2872{2873int name;2874vram[index] = data;2875MARK_BG_DIRTY(index);2876}28772878#ifdef LOGVDP2879error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);2880#endif2881}2882else2883{2884/* CRAM address */2885int index = addr & 0x1F;28862887/* Pointer to CRAM word */2888uint16 *p = (uint16 *)&cram[index << 1];28892890/* Check if CRAM data is being modified */2891if (data != *p)2892{2893/* Write CRAM data */2894*p = data;28952896/* Update color palette */2897color_update_m4(index, data);28982899/* Update backdrop color */2900if (index == (0x10 | (border & 0x0F)))2901{2902color_update_m4(0x40, data);2903}2904}2905#ifdef LOGVDP2906error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, addr, data, Z80.pc.w.l);2907#endif2908}29092910/* Update read buffer */2911fifo[0] = data;29122913/* Update address register */2914addr++;2915}29162917static void vdp_z80_data_w_gg(unsigned int data)2918{2919/* Clear pending flag */2920pending = 0;29212922if (code < 3)2923{2924int index;29252926/* Check if we are already on next line*/2927int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2928if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2929{2930/* Render next line */2931v_counter = line;2932render_line(line);2933}29342935/* VRAM address */2936index = addr & 0x3FFF;29372938/* VRAM write */2939if (data != vram[index])2940{2941int name;2942vram[index] = data;2943MARK_BG_DIRTY(index);2944}2945#ifdef LOGVDP2946error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);2947#endif2948}2949else2950{2951if (addr & 1)2952{2953/* Pointer to CRAM word */2954uint16 *p = (uint16 *)&cram[addr & 0x3E];29552956/* 12-bit data word */2957data = (data << 8) | cached_write;29582959/* Check if CRAM data is being modified */2960if (data != *p)2961{2962/* Color index (0-31) */2963int index = (addr >> 1) & 0x1F;29642965/* Write CRAM data */2966*p = data;29672968/* Update color palette */2969color_update_m4(index, data);29702971/* Update backdrop color */2972if (index == (0x10 | (border & 0x0F)))2973{2974color_update_m4(0x40, data);2975}2976}2977}2978else2979{2980/* Latch LSB */2981cached_write = data;2982}2983#ifdef LOGVDP2984error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, addr, data, Z80.pc.w.l);2985#endif2986}29872988/* Update read buffer */2989fifo[0] = data;29902991/* Update address register */2992addr++;2993}29942995static void vdp_z80_data_w_sg(unsigned int data)2996{2997/* VRAM address */2998int index = addr & 0x3FFF;29993000/* Clear pending flag */3001pending = 0;30023003/* 4K address decoding (cf. tms9918a.txt) */3004if (!(reg[1] & 0x80))3005{3006index = (index & 0x203F) | ((index >> 6) & 0x40) | ((index << 1) & 0x1F80);3007}30083009/* VRAM write */3010vram[index] = data;30113012/* Update address register */3013addr++;30143015#ifdef LOGVDP3016error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);3017#endif3018}30193020/*--------------------------------------------------------------------------*/3021/* DMA operations (Mega Drive VDP only) */3022/*--------------------------------------------------------------------------*/30233024void CDLog68k(uint addr, uint flags);30253026/* DMA from 68K bus: $000000-$7FFFFF (external area) */3027static void vdp_dma_68k_ext(unsigned int length)3028{3029uint16 data;30303031/* 68k bus source address */3032uint32 source = (reg[23] << 17) | (dma_src << 1);30333034do3035{3036/* Read data word from 68k bus */3037if (m68k.memory_map[source>>16].read16)3038{3039data = m68k.memory_map[source>>16].read16(source);3040}3041else3042{3043data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF));3044}30453046if(biz_cdcallback)3047{3048//if((code & 0x0F) == 0x01) //VRAM target //lets handle everything here3049{3050CDLog68k(source,eCDLog_Flags_DMASource);3051CDLog68k(source+1,eCDLog_Flags_DMASource);3052}3053}305430553056/* Increment source address */3057source += 2;30583059/* 128k DMA window */3060source = (reg[23] << 17) | (source & 0x1FFFF);30613062/* Write data word to VRAM, CRAM or VSRAM */3063vdp_bus_w(data);3064}3065while (--length);30663067/* Update DMA source address */3068dma_src = (source >> 1) & 0xffff;3069}30703071/* DMA from 68K bus: $800000-$FFFFFF (internal area) except I/O area */3072static void vdp_dma_68k_ram(unsigned int length)3073{3074uint16 data;30753076/* 68k bus source address */3077uint32 source = (reg[23] << 17) | (dma_src << 1);30783079do3080{3081/* access Work-RAM by default */3082data = *(uint16 *)(work_ram + (source & 0xFFFF));30833084/* Increment source address */3085source += 2;30863087/* 128k DMA window */3088source = (reg[23] << 17) | (source & 0x1FFFF);30893090/* Write data word to VRAM, CRAM or VSRAM */3091vdp_bus_w(data);3092}3093while (--length);30943095/* Update DMA source address */3096dma_src = (source >> 1) & 0xffff;3097}30983099/* DMA from 68K bus: $A00000-$A1FFFF (I/O area) specific */3100static void vdp_dma_68k_io(unsigned int length)3101{3102uint16 data;31033104/* 68k bus source address */3105uint32 source = (reg[23] << 17) | (dma_src << 1);31063107do3108{3109/* Z80 area */3110if (source <= 0xA0FFFF)3111{3112/* Return $FFFF only when the Z80 isn't hogging the Z-bus.3113(e.g. Z80 isn't reset and 68000 has the bus) */3114data = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xFFFF)) : 0xFFFF);3115}31163117/* The I/O chip and work RAM try to drive the data bus which results3118in both values being combined in random ways when read.3119We return the I/O chip values which seem to have precedence, */3120else if (source <= 0xA1001F)3121{3122data = io_68k_read((source >> 1) & 0x0F);3123data = (data << 8 | data);3124}31253126/* All remaining locations access work RAM */3127else3128{3129data = *(uint16 *)(work_ram + (source & 0xFFFF));3130}31313132/* Increment source address */3133source += 2;31343135/* 128k DMA window */3136source = (reg[23] << 17) | (source & 0x1FFFF);31373138/* Write data to VRAM, CRAM or VSRAM */3139vdp_bus_w(data);3140}3141while (--length);31423143/* Update DMA source address */3144dma_src = (source >> 1) & 0xffff;3145}31463147/* VRAM Copy */3148static void vdp_dma_copy(unsigned int length)3149{3150/* CD4 should be set (CD0-CD3 ignored) otherwise VDP locks (hard reset needed) */3151if (code & 0x10)3152{3153int name;3154uint8 data;31553156/* VRAM source address */3157uint16 source = dma_src;31583159do3160{3161/* Read byte from adjacent VRAM source address */3162data = READ_BYTE(vram, source ^ 1);31633164/* Intercept writes to Sprite Attribute Table */3165if ((addr & sat_base_mask) == satb)3166{3167/* Update internal SAT */3168WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data);3169}31703171/* Write byte to adjacent VRAM destination address */3172WRITE_BYTE(vram, addr ^ 1, data);31733174/* Update pattern cache */3175MARK_BG_DIRTY(addr);31763177/* Increment VRAM source address */3178source++;31793180/* Increment VRAM destination address */3181addr += reg[15];3182}3183while (--length);31843185/* Update DMA source address */3186dma_src = source;3187}3188}31893190/* DMA Fill */3191static void vdp_dma_fill(unsigned int length)3192{3193/* Check destination code (CD0-CD3) */3194switch (code & 0x0F)3195{3196case 0x01: /* VRAM */3197{3198int name;31993200/* Get source data from last written FIFO entry */3201uint8 data = fifo[(fifo_idx+3)&3] >> 8;32023203do3204{3205/* Intercept writes to Sprite Attribute Table */3206if ((addr & sat_base_mask) == satb)3207{3208/* Update internal SAT */3209WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data);3210}32113212/* Write byte to adjacent VRAM address */3213WRITE_BYTE(vram, addr ^ 1, data);32143215/* Update pattern cache */3216MARK_BG_DIRTY (addr);32173218/* Increment VRAM address */3219addr += reg[15];3220}3221while (--length);3222break;3223}32243225case 0x03: /* CRAM */3226{3227/* Get source data from next available FIFO entry */3228uint16 data = fifo[fifo_idx];32293230/* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */3231data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1);32323233do3234{3235/* Pointer to CRAM 9-bit word */3236uint16 *p = (uint16 *)&cram[addr & 0x7E];32373238/* Check if CRAM data is being modified */3239if (data != *p)3240{3241/* CRAM index (64 words) */3242int index = (addr >> 1) & 0x3F;32433244/* Write CRAM data */3245*p = data;32463247/* Color entry 0 of each palette is never displayed (transparent pixel) */3248if (index & 0x0F)3249{3250/* Update color palette */3251color_update_m5(index, data);3252}32533254/* Update backdrop color */3255if (index == border)3256{3257color_update_m5(0x00, data);3258}3259}32603261/* Increment CRAM address */3262addr += reg[15];3263}3264while (--length);3265break;3266}32673268case 0x05: /* VSRAM */3269{3270/* Get source data from next available FIFO entry */3271uint16 data = fifo[fifo_idx];32723273do3274{3275/* Write VSRAM data */3276*(uint16 *)&vsram[addr & 0x7E] = data;32773278/* Increment VSRAM address */3279addr += reg[15];3280}3281while (--length);3282break;3283}32843285default:3286{3287/* invalid destination does nothing (Williams Greatest Hits after soft reset) */32883289/* address is still incremented */3290addr += reg[15] * length;3291}3292}3293}329432953296