/***************************************************************************************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}204205void vdp_invalidate_full_cache(void)206{207bg_list_index = 0x800;208for (int i=0;i<bg_list_index;i++)209{210bg_name_list[i] = i;211bg_name_dirty[i] = 0xFF;212}213}214215/*--------------------------------------------------------------------------*/216/* Init, reset, context functions */217/*--------------------------------------------------------------------------*/218219void vdp_init(void)220{221/* PAL/NTSC timings */222lines_per_frame = vdp_pal ? 313: 262;223224/* CPU interrupt line(s)*/225if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)226{227/* 68k cpu */228set_irq_line = m68k_set_irq;229set_irq_line_delay = m68k_set_irq_delay;230}231else232{233/* Z80 cpu */234set_irq_line = z80_set_irq_line;235set_irq_line_delay = z80_set_irq_line;236}237}238239void vdp_reset(void)240{241int i;242243memset ((char *) sat, 0, sizeof (sat));244memset ((char *) vram, 0, sizeof (vram));245memset ((char *) cram, 0, sizeof (cram));246memset ((char *) vsram, 0, sizeof (vsram));247memset ((char *) reg, 0, sizeof (reg));248249addr = 0;250addr_latch = 0;251code = 0;252pending = 0;253border = 0;254hint_pending = 0;255vint_pending = 0;256dmafill = 0;257dma_src = 0;258dma_type = 0;259dma_length = 0;260dma_endCycles = 0;261odd_frame = 0;262im2_flag = 0;263interlaced = 0;264fifo_write_cnt = 0;265fifo_cycles = 0;266fifo_slots = 0;267fifo_idx = 0;268cached_write = -1;269fifo_byte_access = 1;270271ntab = 0;272ntbb = 0;273ntwb = 0;274satb = 0;275hscb = 0;276277vscroll = 0;278279hscroll_mask = 0x00;280playfield_shift = 6;281playfield_col_mask = 0x0F;282playfield_row_mask = 0x0FF;283sat_base_mask = 0xFE00;284sat_addr_mask = 0x01FF;285286/* reset pattern cache changes */287bg_list_index = 0;288memset ((char *) bg_name_dirty, 0, sizeof (bg_name_dirty));289memset ((char *) bg_name_list, 0, sizeof (bg_name_list));290291/* default HVC */292hvc_latch = 0x10000;293hctab = cycle2hc32;294vc_max = vc_table[0][vdp_pal];295v_counter = lines_per_frame - 1;296297/* default Window clipping */298window_clip(0,0);299300/* reset VDP status (FIFO empty flag is set) */301if (system_hw & SYSTEM_MD)302{303status = vdp_pal | 0x200;304}305else306{307status = 0;308}309310/* default display area */311bitmap.viewport.w = 256;312bitmap.viewport.h = 192;313bitmap.viewport.ow = 256;314bitmap.viewport.oh = 192;315316/* default sprite pixel width */317max_sprite_pixels = 256;318319/* default overscan area */320if ((system_hw == SYSTEM_GG) && !config.gg_extra)321{322/* Display area reduced to 160x144 if overscan is disabled */323bitmap.viewport.x = (config.overscan & 2) ? 14 : -48;324bitmap.viewport.y = (config.overscan & 1) ? (24 * (vdp_pal + 1)) : -24;325}326else327{328bitmap.viewport.x = (config.overscan & 2) * 7;329bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);330}331332/* default rendering mode */333update_bg_pattern_cache = update_bg_pattern_cache_m4;334if (system_hw < SYSTEM_MD)335{336/* Mode 0 */337render_bg = render_bg_m0;338render_obj = render_obj_tms;339parse_satb = parse_satb_tms;340}341else342{343/* Mode 4 */344render_bg = render_bg_m4;345render_obj = render_obj_m4;346parse_satb = parse_satb_m4;347}348349/* default 68k bus interface (Mega Drive VDP only) */350vdp_68k_data_w = vdp_68k_data_w_m4;351vdp_68k_data_r = vdp_68k_data_r_m4;352353/* default Z80 bus interface */354switch (system_hw)355{356case SYSTEM_SG:357{358/* SG-1000 VDP (TMS99xx) */359vdp_z80_data_w = vdp_z80_data_w_sg;360vdp_z80_data_r = vdp_z80_data_r_m4;361break;362}363364case SYSTEM_GG:365{366/* Game Gear VDP */367vdp_z80_data_w = vdp_z80_data_w_gg;368vdp_z80_data_r = vdp_z80_data_r_m4;369break;370}371372case SYSTEM_MARKIII:373case SYSTEM_SMS:374case SYSTEM_SMS2:375case SYSTEM_GGMS:376{377/* Master System or Game Gear (in MS compatibility mode) VDP */378vdp_z80_data_w = vdp_z80_data_w_ms;379vdp_z80_data_r = vdp_z80_data_r_m4;380break;381}382383default:384{385/* Mega Drive VDP (in MS compatibility mode) */386vdp_z80_data_w = vdp_z80_data_w_m4;387vdp_z80_data_r = vdp_z80_data_r_m4;388break;389}390}391392/* SG-1000 specific */393if (system_hw == SYSTEM_SG)394{395/* 16k address decoding by default (Magical Kid Wiz) */396vdp_reg_w(1, 0x80, 0);397398/* no H-INT on TMS99xx */399vdp_reg_w(10, 0xFF, 0);400}401402/* Master System specific */403else if ((system_hw & SYSTEM_SMS) && (!(config.bios & 1) || !(system_bios & SYSTEM_SMS)))404{405/* force registers initialization (only if Master System BIOS is disabled or not loaded) */406vdp_reg_w(0 , 0x36, 0);407vdp_reg_w(1 , 0x80, 0);408vdp_reg_w(2 , 0xFF, 0);409vdp_reg_w(3 , 0xFF, 0);410vdp_reg_w(4 , 0xFF, 0);411vdp_reg_w(5 , 0xFF, 0);412vdp_reg_w(6 , 0xFF, 0);413vdp_reg_w(10, 0xFF, 0);414415/* Mode 4 */416render_bg = render_bg_m4;417render_obj = render_obj_m4;418parse_satb = parse_satb_m4;419}420421/* Mega Drive specific */422else if (((system_hw == SYSTEM_MD) || (system_hw == SYSTEM_MCD)) && (config.bios & 1) && !(system_bios & SYSTEM_MD))423{424/* force registers initialization (only if TMSS model is emulated and BOOT ROM is not loaded) */425vdp_reg_w(0 , 0x04, 0);426vdp_reg_w(1 , 0x04, 0);427vdp_reg_w(10, 0xFF, 0);428vdp_reg_w(12, 0x81, 0);429vdp_reg_w(15, 0x02, 0);430}431432/* reset color palette */433for(i = 0; i < 0x20; i ++)434{435color_update_m4(i, 0x00);436}437color_update_m4(0x40, 0x00);438}439440/*--------------------------------------------------------------------------*/441/* DMA update function (Mega Drive VDP only) */442/*--------------------------------------------------------------------------*/443444void vdp_dma_update(unsigned int cycles)445{446int dma_cycles, dma_bytes;447448/* DMA transfer rate (bytes per line)449450According to the manual, here's a table that describes the transfer451rates of each of the three DMA types:452453DMA Mode Width Display Transfer Count454-----------------------------------------------------45568K > VDP 32-cell Active 16456Blanking 16745740-cell Active 18458Blanking 205459VRAM Fill 32-cell Active 15460Blanking 16646140-cell Active 17462Blanking 204463VRAM Copy 32-cell Active 8464Blanking 8346540-cell Active 9466Blanking 102467468'Active' is the active display period, 'Blanking' is either the vertical469blanking period or when the display is forcibly blanked via register #1.470471The above transfer counts are all in bytes, unless the destination is472CRAM or VSRAM for a 68K > VDP transfer, in which case it is in words.473*/474unsigned int rate = dma_timing[(status & 8) || !(reg[1] & 0x40)][reg[12] & 1];475476/* Adjust for 68k bus DMA to VRAM (one word = 2 access) or DMA Copy (one read + one write = 2 access) */477rate = rate >> (dma_type & 1);478479/* Remaining DMA cycles */480if (status & 8)481{482/* Process DMA until the end of VBLANK */483/* NOTE: DMA timings can not change during VBLANK because active display width cannot be modified. */484/* Indeed, writing VDP registers during DMA is either impossible (when doing DMA from 68k bus, CPU */485/* is locked) or will abort DMA operation (in case of DMA Fill or Copy). */486dma_cycles = (lines_per_frame * MCYCLES_PER_LINE) - cycles;487}488else489{490/* Process DMA until the end of current line */491dma_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - cycles;492}493494/* Remaining DMA bytes for that line */495dma_bytes = (dma_cycles * rate) / MCYCLES_PER_LINE;496497#ifdef LOGVDP498error("[%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));499#endif500501/* Check if DMA can be finished before the end of current line */502if (dma_length < dma_bytes)503{504/* Adjust remaining DMA bytes */505dma_bytes = dma_length;506dma_cycles = (dma_bytes * MCYCLES_PER_LINE) / rate;507}508509/* Update DMA timings */510if (dma_type < 2)511{512/* 68K is frozen during DMA from 68k bus */513m68k.cycles = cycles + dma_cycles;514#ifdef LOGVDP515error("-->CPU frozen for %d cycles\n", dma_cycles);516#endif517}518else519{520/* Set DMA Busy flag */521status |= 0x02;522523/* 68K is still running, set DMA end cycle */524dma_endCycles = cycles + dma_cycles;525#ifdef LOGVDP526error("-->DMA ends in %d cycles\n", dma_cycles);527#endif528}529530/* Process DMA */531if (dma_bytes > 0)532{533/* Update DMA length */534dma_length -= dma_bytes;535536/* Process DMA operation */537dma_func[reg[23] >> 4](dma_bytes);538539/* Check if DMA is finished */540if (!dma_length)541{542/* DMA source address registers are incremented during DMA (even DMA Fill) */543uint16 end = reg[21] + (reg[22] << 8) + reg[19] + (reg[20] << 8);544reg[21] = end & 0xff;545reg[22] = end >> 8;546547/* DMA length registers are decremented during DMA */548reg[19] = reg[20] = 0;549550/* perform cached write, if any */551if (cached_write >= 0)552{553vdp_68k_ctrl_w(cached_write);554cached_write = -1;555}556}557}558}559560561/*--------------------------------------------------------------------------*/562/* Control port access functions */563/*--------------------------------------------------------------------------*/564565void vdp_68k_ctrl_w(unsigned int data)566{567/* Check pending flag */568if (pending == 0)569{570/* A single long word write instruction could have started DMA with the first word */571if (dma_length)572{573/* 68k is frozen during 68k bus DMA */574/* Second word should be written after DMA completion */575/* See Formula One & Kawasaki Superbike Challenge */576if (dma_type < 2)577{578/* Latch second control word for later */579cached_write = data;580return;581}582}583584/* Check CD0-CD1 bits */585if ((data & 0xC000) == 0x8000)586{587/* VDP register write */588vdp_reg_w((data >> 8) & 0x1F, data & 0xFF, m68k.cycles);589}590else591{592/* Set pending flag (Mode 5 only) */593pending = reg[1] & 4;594}595596/* Update address and code registers */597addr = addr_latch | (data & 0x3FFF);598code = ((code & 0x3C) | ((data >> 14) & 0x03));599}600else601{602/* Clear pending flag */603pending = 0;604605/* Save address bits A15 and A14 */606addr_latch = (data & 3) << 14;607608/* Update address and code registers */609addr = addr_latch | (addr & 0x3FFF);610code = ((code & 0x03) | ((data >> 2) & 0x3C));611612/* Detect DMA operation (CD5 bit set) */613if (code & 0x20)614{615/* DMA must be enabled */616if (reg[1] & 0x10)617{618/* DMA type */619switch (reg[23] >> 6)620{621case 2:622{623/* DMA Fill */624dma_type = 2;625626/* DMA is pending until next DATA port write */627dmafill = 1;628629/* Set DMA Busy flag */630status |= 0x02;631632/* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */633dma_endCycles = 0xffffffff;634break;635}636637case 3:638{639/* DMA Copy */640dma_type = 3;641642/* DMA length */643dma_length = (reg[20] << 8) | reg[19];644645/* Zero DMA length (pre-decrementing counter) */646if (!dma_length)647{648dma_length = 0x10000;649}650651/* DMA source address */652dma_src = (reg[22] << 8) | reg[21];653654/* Trigger DMA */655vdp_dma_update(m68k.cycles);656break;657}658659default:660{661/* DMA from 68k bus */662dma_type = (code & 0x06) ? 0 : 1;663664/* DMA length */665dma_length = (reg[20] << 8) | reg[19];666667/* Zero DMA length (pre-decrementing counter) */668if (!dma_length)669{670dma_length = 0x10000;671}672673/* DMA source address */674dma_src = (reg[22] << 8) | reg[21];675676/* Transfer from SVP ROM/RAM ($000000-$3fffff) or CD Word-RAM ($200000-$3fffff/$600000-$7fffff) */677if (((system_hw == SYSTEM_MCD) && ((reg[23] & 0x70) == ((scd.cartridge.boot >> 1) + 0x10))) || (svp && !(reg[23] & 0x60)))678{679/* source data is available with one cycle delay, i.e first word written by VDP is */680/* previous data being held on 68k bus at that time, then source words are written */681/* normally to VDP RAM, with only last source word being ignored */682addr += reg[15];683dma_length--;684}685686/* Trigger DMA */687vdp_dma_update(m68k.cycles);688break;689}690}691}692}693}694695/*696FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace)697--------------------------------------------------------------------------698Each VRAM access is byte wide, so one VRAM write (word) need two slot access.699700NOTE: Invalid code 0x02 (register write) should not behave the same as VRAM701access, i.e data is ignored and only one access slot is used for each word,702BUT a few games ("Clue", "Microcosm") which accidentally corrupt code value703will have issues when emulating FIFO timings. They likely work fine on real704hardware because of periodical 68k wait-states which have been observed and705would naturaly add some delay between writes. Until those wait-states are706accurately measured and emulated, delay is forced when invalid code value707is being used.708*/709fifo_byte_access = ((code & 0x0F) <= 0x02);710}711712/* Mega Drive VDP control port specific (MS compatibility mode) */713void vdp_z80_ctrl_w(unsigned int data)714{715switch (pending)716{717case 0:718{719/* Latch LSB */720addr_latch = data;721722/* Set LSB pending flag */723pending = 1;724return;725}726727case 1:728{729/* Update address and code registers */730addr = (addr & 0xC000) | ((data & 0x3F) << 8) | addr_latch ;731code = ((code & 0x3C) | ((data >> 6) & 0x03));732733if ((code & 0x03) == 0x02)734{735/* VDP register write */736vdp_reg_w(data & 0x1F, addr_latch, Z80.cycles);737738/* Clear pending flag */739pending = 0;740return;741}742743/* Set Mode 5 pending flag */744pending = (reg[1] & 4) >> 1;745746if (!pending && !(code & 0x03))747{748/* Process VRAM read */749fifo[0] = vram[addr & 0x3FFF];750751/* Increment address register */752addr += (reg[15] + 1);753}754return;755}756757case 2:758{759/* Latch LSB */760addr_latch = data;761762/* Set LSB pending flag */763pending = 3;764return;765}766767case 3:768{769/* Clear pending flag */770pending = 0;771772/* Update address and code registers */773addr = ((addr_latch & 3) << 14) | (addr & 0x3FFF);774code = ((code & 0x03) | ((addr_latch >> 2) & 0x3C));775776/* Detect DMA operation (CD5 bit set) */777if (code & 0x20)778{779/* DMA should be enabled */780if (reg[1] & 0x10)781{782/* DMA type */783switch (reg[23] >> 6)784{785case 2:786{787/* DMA Fill will be triggered by next write to DATA port */788dmafill = 1;789790/* Set DMA Busy flag */791status |= 0x02;792793/* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */794dma_endCycles = 0xffffffff;795break;796}797798case 3:799{800/* DMA copy */801dma_type = 3;802803/* DMA length */804dma_length = (reg[20] << 8) | reg[19];805806/* Zero DMA length (pre-decrementing counter) */807if (!dma_length)808{809dma_length = 0x10000;810}811812/* DMA source address */813dma_src = (reg[22] << 8) | reg[21];814815/* Trigger DMA */816vdp_dma_update(Z80.cycles);817break;818}819820default:821{822/* DMA from 68k bus does not work when Z80 is in control */823break;824}825}826}827}828}829return;830}831}832833/* Master System & Game Gear VDP control port specific */834void vdp_sms_ctrl_w(unsigned int data)835{836if(pending == 0)837{838/* Update address register LSB */839addr = (addr & 0x3F00) | (data & 0xFF);840841/* Latch LSB */842addr_latch = data;843844/* Set LSB pending flag */845pending = 1;846}847else848{849/* Update address and code registers */850code = (data >> 6) & 3;851addr = (data << 8 | addr_latch) & 0x3FFF;852853/* Clear pending flag */854pending = 0;855856if (code == 0)857{858/* Process VRAM read */859fifo[0] = vram[addr & 0x3FFF];860861/* Increment address register */862addr = (addr + 1) & 0x3FFF;863return;864}865866if (code == 2)867{868/* Save current VDP mode */869int mode, prev = (reg[0] & 0x06) | (reg[1] & 0x18);870871/* Write VDP register 0-15 */872vdp_reg_w(data & 0x0F, addr_latch, Z80.cycles);873874/* Check VDP mode changes */875mode = (reg[0] & 0x06) | (reg[1] & 0x18);876prev ^= mode;877878if (prev)879{880/* Check for extended modes */881if (system_hw > SYSTEM_SMS)882{883int height;884885if (mode == 0x0E) /* M1=0,M2=1,M3=1,M4=1 */886{887/* Mode 4 extended (240 lines) */888height = 240;889890/* Update vertical counter max value */891vc_max = vc_table[3][vdp_pal];892}893else if (mode == 0x16) /* M1=1,M2=1,M3=0,M4=1 */894{895/* Mode 4 extended (224 lines) */896height = 224;897898/* Update vertical counter max value */899vc_max = vc_table[1][vdp_pal];900}901else902{903/* Mode 4 default (224 lines) */904height = 192;905906/* Default vertical counter max value */907vc_max = vc_table[0][vdp_pal];908}909910if (height != bitmap.viewport.h)911{912if (status & 8)913{914/* viewport changes should be applied on next frame */915bitmap.viewport.changed |= 2;916}917else918{919/* update active display */920bitmap.viewport.h = height;921922/* update vertical overscan */923if (config.overscan & 1)924{925bitmap.viewport.y = (240 + 48*vdp_pal - height) >> 1;926}927else928{929if ((system_hw == SYSTEM_GG) && !config.gg_extra)930{931/* Display area reduced to 160x144 */932bitmap.viewport.y = (144 - height) / 2;933}934else935{936bitmap.viewport.y = 0;937}938}939}940}941}942943/* Rendering mode */944switch (mode)945{946case 0x00: /* Graphics I */947{948render_bg = render_bg_m0;949break;950}951952case 0x10: /* Text */953{954render_bg = render_bg_m1;955break;956}957958case 0x02: /* Graphics II */959{960render_bg = render_bg_m2;961break;962}963964case 0x12: /* Text (Extended PG) */965{966render_bg = render_bg_m1x;967break;968}969970case 0x08: /* Multicolor */971{972render_bg = render_bg_m3;973break;974}975976case 0x18: /* Invalid (1+3) */977{978render_bg = render_bg_inv;979break;980}981982case 0x0A: /* Multicolor (Extended PG) */983{984render_bg = render_bg_m3x;985break;986}987988case 0x1A: /* Invalid (1+2+3) */989{990render_bg = render_bg_inv;991break;992}993994default: /* Mode 4 */995{996render_bg = render_bg_m4;997break;998}999}10001001/* Mode switching */1002if (prev & 0x04)1003{1004int i;10051006if (mode & 0x04)1007{1008/* Mode 4 sprites */1009parse_satb = parse_satb_m4;1010render_obj = render_obj_m4;10111012/* force BG cache update*/1013bg_list_index = 0x200;1014}1015else1016{1017/* TMS-mode sprites */1018parse_satb = parse_satb_tms;1019render_obj = render_obj_tms;10201021/* BG cache is not used */1022bg_list_index = 0;1023}10241025/* reinitialize palette */1026for(i = 0; i < 0x20; i ++)1027{1028color_update_m4(i, *(uint16 *)&cram[i << 1]);1029}1030color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);1031}1032}1033}1034}1035}10361037/* SG-1000 VDP (TMS99xx) control port specific */1038void vdp_tms_ctrl_w(unsigned int data)1039{1040if(pending == 0)1041{1042/* Latch LSB */1043addr_latch = data;10441045/* Set LSB pending flag */1046pending = 1;1047}1048else1049{1050/* Update address and code registers */1051code = (data >> 6) & 3;1052addr = (data << 8 | addr_latch) & 0x3FFF;10531054/* Clear pending flag */1055pending = 0;10561057if (code == 0)1058{1059/* Process VRAM read */1060fifo[0] = vram[addr & 0x3FFF];10611062/* Increment address register */1063addr = (addr + 1) & 0x3FFF;1064return;1065}10661067if (code & 2)1068{1069/* VDP register index (0-7) */1070data &= 0x07;10711072/* Write VDP register */1073vdp_reg_w(data, addr_latch, Z80.cycles);10741075/* Check VDP mode changes */1076if (data < 2)1077{1078int mode = (reg[0] & 0x02) | (reg[1] & 0x18);10791080/* Rendering mode */1081switch (mode)1082{1083case 0x00: /* Graphics I */1084{1085render_bg = render_bg_m0;1086break;1087}10881089case 0x10: /* Text */1090{1091render_bg = render_bg_m1;1092break;1093}10941095case 0x02: /* Graphics II */1096{1097render_bg = render_bg_m2;1098break;1099}11001101case 0x12: /* Text (Extended PG) */1102{1103render_bg = render_bg_m1x;1104break;1105}11061107case 0x08: /* Multicolor */1108{1109render_bg = render_bg_m3;1110break;1111}11121113case 0x18: /* Invalid (1+3) */1114{1115render_bg = render_bg_inv;1116break;1117}11181119case 0x0A: /* Multicolor (Extended PG) */1120{1121render_bg = render_bg_m3x;1122break;1123}11241125case 0x1A: /* Invalid (1+2+3) */1126{1127render_bg = render_bg_inv;1128break;1129}1130}1131}1132}1133}1134}11351136/*1137* Status register1138*1139* Bits1140* 0 NTSC(0)/PAL(1)1141* 1 DMA Busy1142* 2 During HBlank1143* 3 During VBlank1144* 4 0:1 even:odd field (interlaced modes only)1145* 5 Sprite collision1146* 6 Too many sprites per line1147* 7 v interrupt occurred1148* 8 Write FIFO full1149* 9 Write FIFO empty1150* 10 - 15 Open Bus1151*/1152unsigned int vdp_68k_ctrl_r(unsigned int cycles)1153{1154unsigned int temp;11551156/* Update FIFO status flags if not empty */1157if (fifo_write_cnt)1158{1159vdp_fifo_update(cycles);1160}11611162/* Check if DMA Busy flag is set */1163if (status & 2)1164{1165/* Check if DMA is finished */1166if (!dma_length && (cycles >= dma_endCycles))1167{1168/* Clear DMA Busy flag */1169status &= 0xFFFD;1170}1171}11721173/* Return VDP status */1174temp = status;11751176/* Clear pending flag */1177pending = 0;11781179/* Clear SOVR & SCOL flags */1180status &= 0xFF9F;11811182/* Display OFF: VBLANK flag is set */1183if (!(reg[1] & 0x40))1184{1185temp |= 0x08;1186}11871188/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican, V.R Troopers, Gouketsuji Ichizoku,...) */1189/* NB: this is not 100% accurate and need to be verified on real hardware */1190if ((cycles % MCYCLES_PER_LINE) < 588)1191{1192temp |= 0x04;1193}11941195#ifdef LOGVDP1196error("[%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));1197#endif1198return (temp);1199}12001201unsigned int vdp_z80_ctrl_r(unsigned int cycles)1202{1203unsigned int temp;12041205/* Cycle-accurate SOVR & VINT flags */1206int line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;12071208/* Check if DMA busy flag is set (Mega Drive VDP specific) */1209if (status & 2)1210{1211/* Check if DMA is finished */1212if (!dma_length && (cycles >= dma_endCycles))1213{1214/* Clear DMA Busy flag */1215status &= 0xFD;1216}1217}12181219/* Check if we are already on next line */1220if (line > v_counter)1221{1222v_counter = line;1223if (line == (bitmap.viewport.h + 1))1224{1225/* set VINT flag (immediately cleared after) */1226status |= 0x80;1227}1228else if ((line >= 0) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))1229{1230/* render next line to check sprites overflow & collision */1231render_line(line);1232}1233}12341235/* Return VDP status */1236temp = status;12371238/* Clear pending flag */1239pending = 0;12401241/* Clear VINT, SOVR & SCOL flags */1242status &= 0xFF1F;12431244/* Mega Drive VDP specific */1245if (system_hw & SYSTEM_MD)1246{1247/* Display OFF: VBLANK flag is set */1248if (!(reg[1] & 0x40))1249{1250temp |= 0x08;1251}12521253/* HBLANK flag */1254if ((cycles % MCYCLES_PER_LINE) < 588)1255{1256temp |= 0x04;1257}1258}1259else if (reg[0] & 0x04)1260{1261/* Mode 4 unused bits (fixes PGA Tour Golf) */1262temp |= 0x1F;1263}12641265/* Cycle-accurate SCOL flag */1266if ((temp & 0x20) && (line == (spr_col >> 8)))1267{1268if (system_hw & SYSTEM_MD)1269{1270/* COL flag is set at HCount 0xFF on MD */1271if ((cycles % MCYCLES_PER_LINE) < 105)1272{1273status |= 0x20;1274temp &= ~0x20;1275}1276}1277else1278{1279/* COL flag is set at the pixel it occurs */1280uint8 hc = hctab[(cycles + SMS_CYCLE_OFFSET + 15) % MCYCLES_PER_LINE];1281if ((hc < (spr_col & 0xff)) || (hc > 0xf3))1282{1283status |= 0x20;1284temp &= ~0x20;1285}1286}1287}12881289/* Clear HINT & VINT pending flags */1290hint_pending = vint_pending = 0;12911292/* Clear Z80 interrupt */1293Z80.irq_state = CLEAR_LINE;12941295#ifdef LOGVDP1296error("[%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);1297#endif1298return (temp);1299}13001301/*--------------------------------------------------------------------------*/1302/* HV Counters */1303/*--------------------------------------------------------------------------*/13041305unsigned int vdp_hvc_r(unsigned int cycles)1306{1307int vc;1308unsigned int data = hvc_latch;13091310/* Check if HVC latch is enabled */1311if (data)1312{1313/* Mode 5: HV-counters are frozen (cf. lightgun games, Sunset Riders logo) */1314if (reg[1] & 0x04)1315{1316#ifdef LOGVDP1317error("[%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));1318#endif1319/* return latched HVC value */1320return (data & 0xffff);1321}1322else1323{1324/* Mode 4: by default, V-counter runs normally & H counter is frozen */1325data &= 0xff;1326}1327}1328else1329{1330/* Cycle-accurate H-Counter (Striker, Mickey Mania, Skitchin, Road Rash I,II,III, Sonic 3D Blast...) */1331data = hctab[cycles % MCYCLES_PER_LINE];1332}13331334/* Cycle-accurate V-Counter (cycle counter starts from line -1) */1335vc = (cycles / MCYCLES_PER_LINE) - 1;13361337/* V-Counter overflow */1338if (vc > vc_max)1339{1340vc -= lines_per_frame;1341}13421343/* Interlaced modes */1344if (interlaced)1345{1346/* Interlace mode 2 (Sonic the Hedgehog 2, Combat Cars) */1347vc <<= im2_flag;13481349/* Replace bit 0 with bit 8 */1350vc = (vc & ~1) | ((vc >> 8) & 1);1351}13521353/* return H-Counter in LSB & V-Counter in MSB */1354data |= ((vc & 0xff) << 8);13551356#ifdef LOGVDP1357error("[%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));1358#endif1359return (data);1360}136113621363/*--------------------------------------------------------------------------*/1364/* Test registers */1365/*--------------------------------------------------------------------------*/13661367void vdp_test_w(unsigned int data)1368{1369#ifdef LOGERROR1370error("Unused VDP Write 0x%x (%08x)\n", data, m68k_get_reg(M68K_REG_PC));1371#endif1372}137313741375/*--------------------------------------------------------------------------*/1376/* 68k interrupt handler (TODO: check how interrupts are handled in Mode 4) */1377/*--------------------------------------------------------------------------*/13781379int vdp_68k_irq_ack(int int_level)1380{1381#ifdef LOGVDP1382error("[%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));1383#endif13841385/* VINT has higher priority (Fatal Rewind) */1386if (vint_pending & reg[1])1387{1388#ifdef LOGVDP1389error("---> VINT cleared\n");1390#endif13911392/* Clear VINT pending flag */1393vint_pending = 0;1394status &= ~0x80;13951396/* Update IRQ status */1397if (hint_pending & reg[0])1398{1399m68k_set_irq(4);1400}1401else1402{1403m68k_set_irq(0);1404}1405}1406else1407{1408#ifdef LOGVDP1409error("---> HINT cleared\n");1410#endif14111412/* Clear HINT pending flag */1413hint_pending = 0;14141415/* Update IRQ status */1416m68k_set_irq(0);1417}14181419return M68K_INT_ACK_AUTOVECTOR;1420}142114221423/*--------------------------------------------------------------------------*/1424/* VDP registers update function */1425/*--------------------------------------------------------------------------*/14261427static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles)1428{1429#ifdef LOGVDP1430error("[%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));1431#endif14321433/* VDP registers #11 to #23 cannot be updated in Mode 4 (Captain Planet & Avengers, Bass Master Classic Pro Edition) */1434if (!(reg[1] & 4) && (r > 10))1435{1436return;1437}14381439switch(r)1440{1441case 0: /* CTRL #1 */1442{1443/* Look for changed bits */1444r = d ^ reg[0];1445reg[0] = d;14461447/* Line Interrupt */1448if ((r & 0x10) && hint_pending)1449{1450/* Update IRQ status */1451if (vint_pending & reg[1])1452{1453set_irq_line(6);1454}1455else if (d & 0x10)1456{1457set_irq_line_delay(4);1458}1459else1460{1461set_irq_line(0);1462}1463}14641465/* Palette selection */1466if (r & 0x04)1467{1468/* Mega Drive VDP only */1469if (system_hw & SYSTEM_MD)1470{1471/* Reset color palette */1472int i;1473if (reg[1] & 0x04)1474{1475/* Mode 5 */1476color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1477for (i = 1; i < 0x40; i++)1478{1479color_update_m5(i, *(uint16 *)&cram[i << 1]);1480}1481}1482else1483{1484/* Mode 4 */1485for (i = 0; i < 0x20; i++)1486{1487color_update_m4(i, *(uint16 *)&cram[i << 1]);1488}1489color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);1490}1491}1492}14931494/* HVC latch (Sunset Riders, Lightgun games) */1495if (r & 0x02)1496{1497/* Mega Drive VDP only */1498if (system_hw & SYSTEM_MD)1499{1500/* Mode 5 only */1501if (reg[1] & 0x04)1502{1503if (d & 0x02)1504{1505/* Latch current HVC */1506hvc_latch = vdp_hvc_r(cycles) | 0x10000;1507}1508else1509{1510/* Free-running HVC */1511hvc_latch = 0;1512}1513}1514}1515}1516break;1517}15181519case 1: /* CTRL #2 */1520{1521/* Look for changed bits */1522r = d ^ reg[1];1523reg[1] = d;15241525/* Display status (modified during active display) */1526if ((r & 0x40) && (v_counter < bitmap.viewport.h))1527{1528/* Cycle offset vs HBLANK */1529int offset = cycles - mcycles_vdp;1530if (offset <= 860)1531{1532/* Sprite rendering is limited if display was disabled during HBLANK (Mickey Mania 3d level, Overdrive Demo) */1533if (d & 0x40)1534{1535/* NB: This is not 100% accurate. On real hardware, the maximal number of rendered sprites pixels */1536/* for the current line (normally 256 or 320 pixels) but also the maximal number of pre-processed */1537/* sprites for the next line (normally 64 or 80 sprites) are both reduced depending on the amount */1538/* of cycles spent with display disabled. Here we only reduce them by a fixed amount when display */1539/* has been reenabled after a specific point within HBLANK. */1540if (offset > 360)1541{1542max_sprite_pixels = 128;1543}1544}15451546/* Redraw entire line (Legend of Galahad, Lemmings 2, Formula One, Kawasaki Super Bike, Deadly Moves,...) */1547render_line(v_counter);15481549/* Restore default */1550max_sprite_pixels = 256 + ((reg[12] & 1) << 6);1551}1552else if (system_hw & SYSTEM_MD)1553{1554/* Active pixel offset */1555if (reg[12] & 1)1556{1557/* dot clock = MCLK / 8 */1558offset = ((offset - 860) / 8) + 16;1559}1560else1561{1562/* dot clock = MCLK / 10 */1563offset = ((offset - 860) / 10) + 16;1564}15651566/* Line is partially blanked (Nigel Mansell's World Championship Racing , Ren & Stimpy Show, ...) */1567if (offset < bitmap.viewport.w)1568{1569if (d & 0x40)1570{1571render_line(v_counter);1572blank_line(v_counter, 0, offset);1573}1574else1575{1576blank_line(v_counter, offset, bitmap.viewport.w - offset);1577}1578}1579}1580}15811582/* Frame Interrupt */1583if ((r & 0x20) && vint_pending)1584{1585/* Update IRQ status */1586if (d & 0x20)1587{1588set_irq_line_delay(6);1589}1590else if (hint_pending & reg[0])1591{1592set_irq_line(4);1593}1594else1595{1596set_irq_line(0);1597}1598}15991600/* Active display height */1601if (r & 0x08)1602{1603/* Mega Drive VDP only */1604if (system_hw & SYSTEM_MD)1605{1606/* Mode 5 only */1607if (d & 0x04)1608{1609/* Changes should be applied on next frame */1610bitmap.viewport.changed |= 2;16111612/* Update vertical counter max value */1613vc_max = vc_table[(d >> 2) & 3][vdp_pal];1614}1615}1616}16171618/* Rendering mode */1619if (r & 0x04)1620{1621/* Mega Drive VDP only */1622if (system_hw & SYSTEM_MD)1623{1624int i;1625if (d & 0x04)1626{1627/* Mode 5 rendering */1628parse_satb = parse_satb_m5;1629update_bg_pattern_cache = update_bg_pattern_cache_m5;1630if (im2_flag)1631{1632render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;1633render_obj = (reg[12] & 0x08) ? render_obj_m5_im2_ste : render_obj_m5_im2;1634}1635else1636{1637render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;1638render_obj = (reg[12] & 0x08) ? render_obj_m5_ste : render_obj_m5;1639}16401641/* Reset color palette */1642color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1643for (i = 1; i < 0x40; i++)1644{1645color_update_m5(i, *(uint16 *)&cram[i << 1]);1646}16471648/* Mode 5 bus access */1649vdp_68k_data_w = vdp_68k_data_w_m5;1650vdp_z80_data_w = vdp_z80_data_w_m5;1651vdp_68k_data_r = vdp_68k_data_r_m5;1652vdp_z80_data_r = vdp_z80_data_r_m5;16531654/* Change display height */1655if (status & 8)1656{1657/* viewport changes should be applied on next frame */1658bitmap.viewport.changed |= 2;1659}1660else1661{1662/* Update current frame active display height */1663bitmap.viewport.h = 224 + ((d & 8) << 1);1664bitmap.viewport.y = (config.overscan & 1) * (8 - (d & 8) + 24*vdp_pal);1665}16661667/* Clear HVC latched value */1668hvc_latch = 0;16691670/* Check if HVC latch bit is set */1671if (reg[0] & 0x02)1672{1673/* Latch current HVC */1674hvc_latch = vdp_hvc_r(cycles) | 0x10000;1675}16761677/* max tiles to invalidate */1678bg_list_index = 0x800;1679}1680else1681{1682/* Mode 4 rendering */1683parse_satb = parse_satb_m4;1684update_bg_pattern_cache = update_bg_pattern_cache_m4;1685render_bg = render_bg_m4;1686render_obj = render_obj_m4;16871688/* Reset color palette */1689for (i = 0; i < 0x20; i++)1690{1691color_update_m4(i, *(uint16 *)&cram[i << 1]);1692}1693color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);16941695/* Mode 4 bus access */1696vdp_68k_data_w = vdp_68k_data_w_m4;1697vdp_z80_data_w = vdp_z80_data_w_m4;1698vdp_68k_data_r = vdp_68k_data_r_m4;1699vdp_z80_data_r = vdp_z80_data_r_m4;17001701if (status & 8)1702{1703/* viewport changes should be applied on next frame */1704bitmap.viewport.changed |= 2;1705}1706else1707{1708/* Update current frame active display */1709bitmap.viewport.h = 192;1710bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);1711}17121713/* Latch current HVC */1714hvc_latch = vdp_hvc_r(cycles) | 0x10000;17151716/* max tiles to invalidate */1717bg_list_index = 0x200;1718}17191720/* Invalidate pattern cache */1721for (i=0;i<bg_list_index;i++)1722{1723bg_name_list[i] = i;1724bg_name_dirty[i] = 0xFF;1725}17261727/* Update vertical counter max value */1728vc_max = vc_table[(d >> 2) & 3][vdp_pal];1729}1730else1731{1732/* No effect (cleared to avoid mode 5 detection elsewhere) */1733reg[1] &= ~0x04;1734}1735}1736break;1737}17381739case 2: /* Plane A Name Table Base */1740{1741reg[2] = d;1742ntab = (d << 10) & 0xE000;17431744/* Plane A Name Table Base changed during HBLANK */1745if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1746{1747/* render entire line */1748render_line(v_counter);1749}1750break;1751}17521753case 3: /* Window Plane Name Table Base */1754{1755reg[3] = d;1756if (reg[12] & 0x01)1757{1758ntwb = (d << 10) & 0xF000;1759}1760else1761{1762ntwb = (d << 10) & 0xF800;1763}17641765/* Window Plane Name Table Base changed during HBLANK */1766if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1767{1768/* render entire line */1769render_line(v_counter);1770}1771break;1772}17731774case 4: /* Plane B Name Table Base */1775{1776reg[4] = d;1777ntbb = (d << 13) & 0xE000;17781779/* Plane B Name Table Base changed during HBLANK (Adventures of Batman & Robin) */1780if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1781{1782/* render entire line */1783render_line(v_counter);1784}17851786break;1787}17881789case 5: /* Sprite Attribute Table Base */1790{1791reg[5] = d;1792satb = (d << 9) & sat_base_mask;1793break;1794}17951796case 7: /* Backdrop color */1797{1798reg[7] = d;17991800/* Check if backdrop color changed */1801d &= 0x3F;18021803if (d != border)1804{1805/* Update backdrop color */1806border = d;18071808/* Reset palette entry */1809if (reg[1] & 4)1810{1811/* Mode 5 */1812color_update_m5(0x00, *(uint16 *)&cram[d << 1]);1813}1814else1815{1816/* Mode 4 */1817color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (d & 0x0F)) << 1]);1818}18191820/* Backdrop color modified during HBLANK (Road Rash 1,2,3)*/1821if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))1822{1823/* remap entire line */1824remap_line(v_counter);1825}1826}1827break;1828}18291830case 8: /* Horizontal Scroll (Mode 4 only) */1831{1832int line;18331834/* Hscroll is latched at HCount 0xF3, HCount 0xF6 on MD */1835/* Line starts at HCount 0xF4, HCount 0xF6 on MD */1836if (system_hw < SYSTEM_MD)1837{1838cycles = cycles + 15;1839}18401841/* Make sure Hscroll has not already been latched */1842line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;1843if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))1844{1845v_counter = line;1846render_line(line);1847}18481849reg[8] = d;1850break;1851}18521853case 11: /* CTRL #3 */1854{1855reg[11] = d;18561857/* Horizontal scrolling mode */1858hscroll_mask = hscroll_mask_table[d & 0x03];18591860/* Vertical Scrolling mode */1861if (d & 0x04)1862{1863render_bg = im2_flag ? render_bg_m5_im2_vs : render_bg_m5_vs;1864}1865else1866{1867render_bg = im2_flag ? render_bg_m5_im2 : render_bg_m5;1868}1869break;1870}18711872case 12: /* CTRL #4 */1873{1874/* Look for changed bits */1875r = d ^ reg[12];1876reg[12] = d;18771878/* Shadow & Highlight mode */1879if (r & 0x08)1880{1881/* Reset color palette */1882int i;1883color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1884for (i = 1; i < 0x40; i++)1885{1886color_update_m5(i, *(uint16 *)&cram[i << 1]);1887}18881889/* Update sprite rendering function */1890if (d & 0x08)1891{1892render_obj = im2_flag ? render_obj_m5_im2_ste : render_obj_m5_ste;1893}1894else1895{1896render_obj = im2_flag ? render_obj_m5_im2 : render_obj_m5;1897}1898}18991900/* Interlaced modes */1901if (r & 0x06)1902{1903/* changes should be applied on next frame */1904bitmap.viewport.changed |= 2;1905}19061907/* Active display width */1908if (r & 0x01)1909{1910if (d & 0x01)1911{1912/* Update display-dependant registers */1913ntwb = (reg[3] << 10) & 0xF000;1914satb = (reg[5] << 9) & 0xFC00;1915sat_base_mask = 0xFC00;1916sat_addr_mask = 0x03FF;19171918/* Update HC table */1919hctab = cycle2hc40;19201921/* Update clipping */1922window_clip(reg[17], 1);19231924/* Max. sprite pixels per line */1925max_sprite_pixels = 320;1926}1927else1928{1929/* Update display-dependant registers */1930ntwb = (reg[3] << 10) & 0xF800;1931satb = (reg[5] << 9) & 0xFE00;1932sat_base_mask = 0xFE00;1933sat_addr_mask = 0x01FF;19341935/* Update HC table */1936hctab = cycle2hc32;19371938/* Update clipping */1939window_clip(reg[17], 0);19401941/* Max. sprite pixels per line */1942max_sprite_pixels = 256;1943}19441945/* Active display width modified during HBLANK (Bugs Bunny Double Trouble) */1946if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))1947{1948/* Update active display width */1949bitmap.viewport.w = 256 + ((d & 1) << 6);19501951/* Redraw entire line */1952render_line(v_counter);1953}1954else if (v_counter == (lines_per_frame - 1))1955{1956/* Update starting frame active display width */1957bitmap.viewport.w = 256 + ((d & 1) << 6);1958}1959else1960{1961/* Changes should be applied on next frame (Golden Axe III intro) */1962/* NB: not 100% accurate but required since backend framebuffer width cannot be modified mid-frame. */1963/* This would require a fixed framebuffer width (based on TV screen aspect ratio) and pixel scaling */1964/* to be done during rendering (depending on active display pixel aspect ratio in H32 or H40 mode). */1965/* Display is generally disabled when this is modified so it shouldn't be really noticeable anyway. */1966bitmap.viewport.changed |= 2;1967}1968}1969break;1970}19711972case 13: /* HScroll Base Address */1973{1974reg[13] = d;1975hscb = (d << 10) & 0xFC00;1976break;1977}19781979case 16: /* Playfield size */1980{1981reg[16] = d;1982playfield_shift = shift_table[(d & 3)];1983playfield_col_mask = col_mask_table[(d & 3)];1984playfield_row_mask = row_mask_table[(d >> 4) & 3];1985break;1986}19871988case 17: /* Window/Plane A vertical clipping */1989{1990reg[17] = d;1991window_clip(d, reg[12] & 1);1992break;1993}19941995default:1996{1997reg[r] = d;1998break;1999}2000}2001}20022003/*--------------------------------------------------------------------------*/2004/* FIFO emulation (Mega Drive VDP specific) */2005/* ---------------------------------------- */2006/* */2007/* CPU access to VRAM, CRAM & VSRAM is limited during active display: */2008/* H32 mode -> 16 access per line */2009/* H40 mode -> 18 access per line */2010/* */2011/* with fixed access slots timings detailled below. */2012/* */2013/* Each VRAM access is byte wide, so one VRAM write (word) need two slots. */2014/* */2015/*--------------------------------------------------------------------------*/20162017static void vdp_fifo_update(unsigned int cycles)2018{2019int slots, count = 0;20202021const int *fifo_timing;20222023const int fifo_cycles_h32[16+2] =2024{2025230, 510, 810, 970, 1130, 1450, 1610, 1770, 2090, 2250, 2410, 2730, 2890, 3050, 3350, 3370,2026MCYCLES_PER_LINE + 230, MCYCLES_PER_LINE + 5102027};20282029const int fifo_cycles_h40[18+2] =2030{2031352, 820, 948, 1076, 1332, 1460, 1588, 1844, 1972, 2100, 2356, 2484, 2612, 2868, 2996, 3124, 3364, 3380,2032MCYCLES_PER_LINE + 352, MCYCLES_PER_LINE + 8202033};203420352036/* number of access slots up to current line */2037if (reg[12] & 0x01)2038{2039fifo_timing = fifo_cycles_h40;2040slots = 18 * (cycles / MCYCLES_PER_LINE);2041}2042else2043{2044fifo_timing = fifo_cycles_h32;2045slots = 16 * (cycles / MCYCLES_PER_LINE);2046}20472048/* number of access slots within current line */2049cycles = cycles % MCYCLES_PER_LINE;2050while (fifo_timing[count] <= cycles)2051{2052count++;2053}20542055/* number of processed FIFO entries since last access */2056slots = (slots + count - fifo_slots) >> fifo_byte_access;20572058if (slots > 0)2059{2060/* process FIFO entries */2061fifo_write_cnt -= slots;20622063/* Clear FIFO full flag */2064status &= 0xFEFF;20652066if (fifo_write_cnt <= 0)2067{2068/* No more FIFO entries */2069fifo_write_cnt = 0;20702071/* Set FIFO empty flag */2072status |= 0x200;2073}20742075/* Update FIFO access slot counter */2076fifo_slots += (slots << fifo_byte_access);2077}20782079/* next FIFO update cycle */2080fifo_cycles = mcycles_vdp + fifo_timing[count | fifo_byte_access];2081}208220832084/*--------------------------------------------------------------------------*/2085/* Internal 16-bit data bus access function (Mode 5 only) */2086/*--------------------------------------------------------------------------*/2087static void vdp_bus_w(unsigned int data)2088{2089/* write data to next FIFO entry */2090fifo[fifo_idx] = data;20912092/* increment FIFO write pointer */2093fifo_idx = (fifo_idx + 1) & 3;20942095/* Check destination code (CD0-CD3) */2096switch (code & 0x0F)2097{2098case 0x01: /* VRAM */2099{2100/* VRAM address */2101int index = addr & 0xFFFE;21022103/* Pointer to VRAM */2104uint16 *p = (uint16 *)&vram[index];21052106/* Byte-swap data if A0 is set */2107if (addr & 1)2108{2109data = ((data >> 8) | (data << 8)) & 0xFFFF;2110}21112112/* Intercept writes to Sprite Attribute Table */2113if ((index & sat_base_mask) == satb)2114{2115/* Update internal SAT */2116*(uint16 *) &sat[index & sat_addr_mask] = data;2117}21182119/* Only write unique data to VRAM */2120if (data != *p)2121{2122int name;21232124/* Write data to VRAM */2125*p = data;21262127/* Update pattern cache */2128MARK_BG_DIRTY (index);2129}21302131#ifdef LOGVDP2132error("[%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));2133#endif2134break;2135}21362137case 0x03: /* CRAM */2138{2139/* Pointer to CRAM 9-bit word */2140uint16 *p = (uint16 *)&cram[addr & 0x7E];21412142/* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */2143data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1);21442145/* Check if CRAM data is being modified */2146if (data != *p)2147{2148/* CRAM index (64 words) */2149int index = (addr >> 1) & 0x3F;21502151/* Write CRAM data */2152*p = data;21532154/* Color entry 0 of each palette is never displayed (transparent pixel) */2155if (index & 0x0F)2156{2157/* Update color palette */2158color_update_m5(index, data);2159}21602161/* Update backdrop color */2162if (index == border)2163{2164color_update_m5(0x00, data);2165}21662167/* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */2168if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))2169{2170/* Remap current line */2171remap_line(v_counter);2172}2173}2174#ifdef LOGVDP2175error("[%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));2176#endif2177break;2178}21792180case 0x05: /* VSRAM */2181{2182*(uint16 *)&vsram[addr & 0x7E] = data;21832184/* 2-cell Vscroll mode */2185if (reg[11] & 0x04)2186{2187/* VSRAM writes during HBLANK (Adventures of Batman & Robin) */2188if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))2189{2190/* Remap current line */2191render_line(v_counter);2192}2193}2194#ifdef LOGVDP2195error("[%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));2196#endif2197break;2198}21992200default:2201{2202/* add some delay until 68k periodical wait-states are accurately emulated ("Clue", "Microcosm") */2203m68k.cycles += 2;2204#ifdef LOGERROR2205error("[%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));2206#endif2207break;2208}2209}22102211/* Increment address register */2212addr += reg[15];2213}221422152216/*--------------------------------------------------------------------------*/2217/* 68k bus interface (Mega Drive VDP only) */2218/*--------------------------------------------------------------------------*/22192220static void vdp_68k_data_w_m4(unsigned int data)2221{2222/* Clear pending flag */2223pending = 0;22242225/* Restricted VDP writes during active display */2226if (!(status & 8) && (reg[1] & 0x40))2227{2228/* Update VDP FIFO */2229vdp_fifo_update(m68k.cycles);22302231/* Clear FIFO empty flag */2232status &= 0xFDFF;22332234/* up to 4 words can be stored */2235if (fifo_write_cnt < 4)2236{2237/* Increment FIFO counter */2238fifo_write_cnt++;22392240/* Set FIFO full flag if 4 words are stored */2241status |= ((fifo_write_cnt & 4) << 6);2242}2243else2244{2245/* CPU is halted until next FIFO entry processing */2246m68k.cycles = fifo_cycles;22472248/* Update FIFO access slot counter */2249fifo_slots = fifo_slots + 1 + fifo_byte_access;2250}2251}22522253/* Check destination code */2254if (code & 0x02)2255{2256/* CRAM index (32 words) */2257int index = addr & 0x1F;22582259/* Pointer to CRAM 9-bit word */2260uint16 *p = (uint16 *)&cram[index << 1];22612262/* Pack 16-bit data (xxx000BBGGRR) to 9-bit CRAM data (xxxBBGGRR) */2263data = ((data & 0xE00) >> 3) | (data & 0x3F);22642265/* Check if CRAM data is being modified */2266if (data != *p)2267{2268/* Write CRAM data */2269*p = data;22702271/* Update color palette */2272color_update_m4(index, data);22732274/* Update backdrop color */2275if (index == (0x10 | (border & 0x0F)))2276{2277color_update_m4(0x40, data);2278}2279}2280}2281else2282{2283/* VRAM address (interleaved format) */2284int index = ((addr << 1) & 0x3FC) | ((addr & 0x200) >> 8) | (addr & 0x3C00);22852286/* Pointer to VRAM */2287uint16 *p = (uint16 *)&vram[index];22882289/* Byte-swap data if A0 is set */2290if (addr & 1)2291{2292data = ((data >> 8) | (data << 8)) & 0xFFFF;2293}22942295/* Only write unique data to VRAM */2296if (data != *p)2297{2298int name;22992300/* Write data to VRAM */2301*p = data;23022303/* Update the pattern cache */2304MARK_BG_DIRTY (index);2305}2306}23072308/* Increment address register (TODO: check how address is incremented in Mode 4) */2309addr += (reg[15] + 1);2310}23112312static void vdp_68k_data_w_m5(unsigned int data)2313{2314/* Clear pending flag */2315pending = 0;23162317/* Restricted VDP writes during active display */2318if (!(status & 8) && (reg[1] & 0x40))2319{2320/* Update VDP FIFO */2321vdp_fifo_update(m68k.cycles);23222323/* Clear FIFO empty flag */2324status &= 0xFDFF;23252326/* up to 4 words can be stored */2327if (fifo_write_cnt < 4)2328{2329/* Increment FIFO counter */2330fifo_write_cnt++;23312332/* Set FIFO full flag if 4 words are stored */2333status |= ((fifo_write_cnt & 4) << 6);2334}2335else2336{2337/* CPU is halted until next FIFO entry processing (Chaos Engine / Soldiers of Fortune, Double Clutch, Titan Overdrive Demo) */2338m68k.cycles = fifo_cycles;23392340/* Update FIFO access slot counter */2341fifo_slots += (1 + fifo_byte_access);2342}2343}23442345/* Write data */2346vdp_bus_w(data);23472348/* Check if DMA Fill is pending */2349if (dmafill)2350{2351/* Clear DMA Fill pending flag */2352dmafill = 0;23532354/* DMA length */2355dma_length = (reg[20] << 8) | reg[19];23562357/* Zero DMA length (pre-decrementing counter) */2358if (!dma_length)2359{2360dma_length = 0x10000;2361}23622363/* Trigger DMA */2364vdp_dma_update(m68k.cycles);2365}2366}23672368static unsigned int vdp_68k_data_r_m4(void)2369{2370/* VRAM address (interleaved format) */2371int index = ((addr << 1) & 0x3FC) | ((addr & 0x200) >> 8) | (addr & 0x3C00);23722373/* Clear pending flag */2374pending = 0;23752376/* Increment address register (TODO: check how address is incremented in Mode 4) */2377addr += (reg[15] + 1);23782379/* Read VRAM data */2380return *(uint16 *) &vram[index];2381}23822383static unsigned int vdp_68k_data_r_m5(void)2384{2385uint16 data = 0;23862387/* Clear pending flag */2388pending = 0;23892390/* Check destination code (CD0-CD3) & CD4 */2391switch (code & 0x1F)2392{2393case 0x00:2394{2395/* read two bytes from VRAM */2396data = *(uint16 *)&vram[addr & 0xFFFE];23972398#ifdef LOGVDP2399error("[%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));2400#endif2401break;2402}24032404case 0x04:2405{2406/* VSRAM index */2407int index = addr & 0x7E;24082409/* Check against VSRAM max size (80 x 11-bits) */2410if (index >= 0x50)2411{2412/* Wrap to address 0 (TODO: check if still true with Genesis 3 model) */2413index = 0;2414}24152416/* Read 11-bit word from VSRAM */2417data = *(uint16 *)&vsram[index] & 0x7FF;24182419/* Unused bits are set using data from next available FIFO entry */2420data |= (fifo[fifo_idx] & ~0x7FF);24212422#ifdef LOGVDP2423error("[%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));2424#endif2425break;2426}24272428case 0x08:2429{2430/* Read 9-bit word from CRAM */2431data = *(uint16 *)&cram[addr & 0x7E];24322433/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit bus data (BBB0GGG0RRR0) */2434data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);24352436/* Unused bits are set using data from next available FIFO entry */2437data |= (fifo[fifo_idx] & ~0xEEE);24382439#ifdef LOGVDP2440error("[%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));2441#endif2442break;2443}24442445case 0x0c: /* undocumented 8-bit VRAM read */2446{2447/* Read one byte from VRAM adjacent address */2448data = READ_BYTE(vram, addr ^ 1);24492450/* Unused bits are set using data from next available FIFO entry */2451data |= (fifo[fifo_idx] & ~0xFF);24522453#ifdef LOGVDP2454error("[%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));2455#endif2456break;2457}24582459default:2460{2461/* Invalid code value (normally locks VDP, hard reset required) */2462#ifdef LOGERROR2463error("[%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));2464#endif2465break;2466}2467}24682469/* Increment address register */2470addr += reg[15];24712472/* Return data */2473return data;2474}247524762477/*--------------------------------------------------------------------------*/2478/* Z80 bus interface (Mega Drive VDP in Master System compatibility mode) */2479/*--------------------------------------------------------------------------*/24802481static void vdp_z80_data_w_m4(unsigned int data)2482{2483/* Clear pending flag */2484pending = 0;24852486/* Check destination code */2487if (code & 0x02)2488{2489/* CRAM index (32 words) */2490int index = addr & 0x1F;24912492/* Pointer to CRAM word */2493uint16 *p = (uint16 *)&cram[index << 1];24942495/* Check if CRAM data is being modified */2496if (data != *p)2497{2498/* Write CRAM data */2499*p = data;25002501/* Update color palette */2502color_update_m4(index, data);25032504/* Update backdrop color */2505if (index == (0x10 | (border & 0x0F)))2506{2507color_update_m4(0x40, data);2508}2509}2510}2511else2512{2513/* VRAM address */2514int index = addr & 0x3FFF;25152516/* Only write unique data to VRAM */2517if (data != vram[index])2518{2519int name;25202521/* Write data */2522vram[index] = data;25232524/* Update pattern cache */2525MARK_BG_DIRTY(index);2526}2527}25282529/* Increment address register (TODO: check how address is incremented in Mode 4) */2530addr += (reg[15] + 1);2531}25322533static void vdp_z80_data_w_m5(unsigned int data)2534{2535/* Clear pending flag */2536pending = 0;25372538/* Push byte into FIFO */2539fifo[fifo_idx] = data << 8;2540fifo_idx = (fifo_idx + 1) & 3;25412542/* Check destination code (CD0-CD3) */2543switch (code & 0x0F)2544{2545case 0x01: /* VRAM */2546{2547/* VRAM address (write low byte to even address & high byte to odd address) */2548int index = addr ^ 1;25492550/* Intercept writes to Sprite Attribute Table */2551if ((index & sat_base_mask) == satb)2552{2553/* Update internal SAT */2554WRITE_BYTE(sat, index & sat_addr_mask, data);2555}25562557/* Only write unique data to VRAM */2558if (data != READ_BYTE(vram, index))2559{2560int name;25612562/* Write data */2563WRITE_BYTE(vram, index, data);25642565/* Update pattern cache */2566MARK_BG_DIRTY (index);2567}2568break;2569}25702571case 0x03: /* CRAM */2572{2573/* Pointer to CRAM word */2574uint16 *p = (uint16 *)&cram[addr & 0x7E];25752576/* Pack 8-bit value into 9-bit CRAM data */2577if (addr & 1)2578{2579/* Write high byte (0000BBB0 -> BBBxxxxxx) */2580data = (*p & 0x3F) | ((data & 0x0E) << 5);2581}2582else2583{2584/* Write low byte (GGG0RRR0 -> xxxGGGRRR) */2585data = (*p & 0x1C0) | ((data & 0x0E) >> 1)| ((data & 0xE0) >> 2);2586}25872588/* Check if CRAM data is being modified */2589if (data != *p)2590{2591/* CRAM index (64 words) */2592int index = (addr >> 1) & 0x3F;25932594/* Write CRAM data */2595*p = data;25962597/* Color entry 0 of each palette is never displayed (transparent pixel) */2598if (index & 0x0F)2599{2600/* Update color palette */2601color_update_m5(index, data);2602}26032604/* Update backdrop color */2605if (index == border)2606{2607color_update_m5(0x00, data);2608}2609}2610break;2611}26122613case 0x05: /* VSRAM */2614{2615/* Write low byte to even address & high byte to odd address */2616WRITE_BYTE(vsram, (addr & 0x7F) ^ 1, data);2617break;2618}2619}26202621/* Increment address register */2622addr += reg[15];26232624/* Check if DMA Fill is pending */2625if (dmafill)2626{2627/* Clear DMA Fill pending flag */2628dmafill = 0;26292630/* DMA length */2631dma_length = (reg[20] << 8) | reg[19];26322633/* Zero DMA length (pre-decrementing counter) */2634if (!dma_length)2635{2636dma_length = 0x10000;2637}26382639/* Trigger DMA */2640vdp_dma_update(Z80.cycles);2641}2642}26432644static unsigned int vdp_z80_data_r_m4(void)2645{2646/* Read buffer */2647unsigned int data = fifo[0];26482649/* Clear pending flag */2650pending = 0;26512652/* Process next read */2653fifo[0] = vram[addr & 0x3FFF];26542655/* Increment address register (TODO: check how address is incremented in Mode 4) */2656addr += (reg[15] + 1);26572658/* Return data */2659return data;2660}26612662static unsigned int vdp_z80_data_r_m5(void)2663{2664unsigned int data = 0;26652666/* Clear pending flag */2667pending = 0;26682669/* Check destination code (CD0-CD3) & CD4 */2670switch (code & 0x1F)2671{2672case 0x00: /* VRAM */2673{2674/* Return low byte from even address & high byte from odd address */2675data = READ_BYTE(vram, addr ^ 1);2676break;2677}26782679case 0x04: /* VSRAM */2680{2681/* Return low byte from even address & high byte from odd address */2682data = READ_BYTE(vsram, (addr & 0x7F) ^ 1);2683break;2684}26852686case 0x08: /* CRAM */2687{2688/* Read CRAM data */2689data = *(uint16 *)&cram[addr & 0x7E];26902691/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit data (BBB0GGG0RRR0) */2692data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);26932694/* Return low byte from even address & high byte from odd address */2695if (addr & 1)2696{2697data = data >> 8;2698}26992700data &= 0xFF;2701break;2702}2703}27042705/* Increment address register */2706addr += reg[15];27072708/* Return data */2709return data;2710}271127122713/*-----------------------------------------------------------------------------*/2714/* Z80 bus interface (Master System, Game Gear & SG-1000 VDP) */2715/*-----------------------------------------------------------------------------*/27162717static void vdp_z80_data_w_ms(unsigned int data)2718{2719/* Clear pending flag */2720pending = 0;27212722if (code < 3)2723{2724int index;27252726/* Check if we are already on next line */2727int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2728if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2729{2730/* Render next line */2731v_counter = line;2732render_line(line);2733}27342735/* VRAM address */2736index = addr & 0x3FFF;27372738/* VRAM write */2739if (data != vram[index])2740{2741int name;2742vram[index] = data;2743MARK_BG_DIRTY(index);2744}27452746#ifdef LOGVDP2747error("[%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);2748#endif2749}2750else2751{2752/* CRAM address */2753int index = addr & 0x1F;27542755/* Pointer to CRAM word */2756uint16 *p = (uint16 *)&cram[index << 1];27572758/* Check if CRAM data is being modified */2759if (data != *p)2760{2761/* Write CRAM data */2762*p = data;27632764/* Update color palette */2765color_update_m4(index, data);27662767/* Update backdrop color */2768if (index == (0x10 | (border & 0x0F)))2769{2770color_update_m4(0x40, data);2771}2772}2773#ifdef LOGVDP2774error("[%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);2775#endif2776}27772778/* Update read buffer */2779fifo[0] = data;27802781/* Update address register */2782addr++;2783}27842785static void vdp_z80_data_w_gg(unsigned int data)2786{2787/* Clear pending flag */2788pending = 0;27892790if (code < 3)2791{2792int index;27932794/* Check if we are already on next line*/2795int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2796if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2797{2798/* Render next line */2799v_counter = line;2800render_line(line);2801}28022803/* VRAM address */2804index = addr & 0x3FFF;28052806/* VRAM write */2807if (data != vram[index])2808{2809int name;2810vram[index] = data;2811MARK_BG_DIRTY(index);2812}2813#ifdef LOGVDP2814error("[%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);2815#endif2816}2817else2818{2819if (addr & 1)2820{2821/* Pointer to CRAM word */2822uint16 *p = (uint16 *)&cram[addr & 0x3E];28232824/* 12-bit data word */2825data = (data << 8) | cached_write;28262827/* Check if CRAM data is being modified */2828if (data != *p)2829{2830/* Color index (0-31) */2831int index = (addr >> 1) & 0x1F;28322833/* Write CRAM data */2834*p = data;28352836/* Update color palette */2837color_update_m4(index, data);28382839/* Update backdrop color */2840if (index == (0x10 | (border & 0x0F)))2841{2842color_update_m4(0x40, data);2843}2844}2845}2846else2847{2848/* Latch LSB */2849cached_write = data;2850}2851#ifdef LOGVDP2852error("[%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);2853#endif2854}28552856/* Update read buffer */2857fifo[0] = data;28582859/* Update address register */2860addr++;2861}28622863static void vdp_z80_data_w_sg(unsigned int data)2864{2865/* VRAM address */2866int index = addr & 0x3FFF;28672868/* Clear pending flag */2869pending = 0;28702871/* 4K address decoding (cf. tms9918a.txt) */2872if (!(reg[1] & 0x80))2873{2874index = (index & 0x203F) | ((index >> 6) & 0x40) | ((index << 1) & 0x1F80);2875}28762877/* VRAM write */2878vram[index] = data;28792880/* Update address register */2881addr++;28822883#ifdef LOGVDP2884error("[%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);2885#endif2886}28872888/*--------------------------------------------------------------------------*/2889/* DMA operations (Mega Drive VDP only) */2890/*--------------------------------------------------------------------------*/28912892void CDLog68k(uint addr, uint flags);28932894/* DMA from 68K bus: $000000-$7FFFFF (external area) */2895static void vdp_dma_68k_ext(unsigned int length)2896{2897uint16 data;28982899/* 68k bus source address */2900uint32 source = (reg[23] << 17) | (dma_src << 1);29012902do2903{2904/* Read data word from 68k bus */2905if (m68k.memory_map[source>>16].read16)2906{2907data = m68k.memory_map[source>>16].read16(source);2908}2909else2910{2911data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF));2912}29132914if(biz_cdcallback)2915{2916//if((code & 0x0F) == 0x01) //VRAM target //lets handle everything here2917{2918CDLog68k(source,eCDLog_Flags_DMASource);2919CDLog68k(source+1,eCDLog_Flags_DMASource);2920}2921}292229232924/* Increment source address */2925source += 2;29262927/* 128k DMA window */2928source = (reg[23] << 17) | (source & 0x1FFFF);29292930/* Write data word to VRAM, CRAM or VSRAM */2931vdp_bus_w(data);2932}2933while (--length);29342935/* Update DMA source address */2936dma_src = (source >> 1) & 0xffff;2937}29382939/* DMA from 68K bus: $800000-$FFFFFF (internal area) except I/O area */2940static void vdp_dma_68k_ram(unsigned int length)2941{2942uint16 data;29432944/* 68k bus source address */2945uint32 source = (reg[23] << 17) | (dma_src << 1);29462947do2948{2949/* access Work-RAM by default */2950data = *(uint16 *)(work_ram + (source & 0xFFFF));29512952/* Increment source address */2953source += 2;29542955/* 128k DMA window */2956source = (reg[23] << 17) | (source & 0x1FFFF);29572958/* Write data word to VRAM, CRAM or VSRAM */2959vdp_bus_w(data);2960}2961while (--length);29622963/* Update DMA source address */2964dma_src = (source >> 1) & 0xffff;2965}29662967/* DMA from 68K bus: $A00000-$A1FFFF (I/O area) specific */2968static void vdp_dma_68k_io(unsigned int length)2969{2970uint16 data;29712972/* 68k bus source address */2973uint32 source = (reg[23] << 17) | (dma_src << 1);29742975do2976{2977/* Z80 area */2978if (source <= 0xA0FFFF)2979{2980/* Return $FFFF only when the Z80 isn't hogging the Z-bus.2981(e.g. Z80 isn't reset and 68000 has the bus) */2982data = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xFFFF)) : 0xFFFF);2983}29842985/* The I/O chip and work RAM try to drive the data bus which results2986in both values being combined in random ways when read.2987We return the I/O chip values which seem to have precedence, */2988else if (source <= 0xA1001F)2989{2990data = io_68k_read((source >> 1) & 0x0F);2991data = (data << 8 | data);2992}29932994/* All remaining locations access work RAM */2995else2996{2997data = *(uint16 *)(work_ram + (source & 0xFFFF));2998}29993000/* Increment source address */3001source += 2;30023003/* 128k DMA window */3004source = (reg[23] << 17) | (source & 0x1FFFF);30053006/* Write data to VRAM, CRAM or VSRAM */3007vdp_bus_w(data);3008}3009while (--length);30103011/* Update DMA source address */3012dma_src = (source >> 1) & 0xffff;3013}30143015/* VRAM Copy */3016static void vdp_dma_copy(unsigned int length)3017{3018/* CD4 should be set (CD0-CD3 ignored) otherwise VDP locks (hard reset needed) */3019if (code & 0x10)3020{3021int name;3022uint8 data;30233024/* VRAM source address */3025uint16 source = dma_src;30263027do3028{3029/* Read byte from adjacent VRAM source address */3030data = READ_BYTE(vram, source ^ 1);30313032/* Intercept writes to Sprite Attribute Table */3033if ((addr & sat_base_mask) == satb)3034{3035/* Update internal SAT */3036WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data);3037}30383039/* Write byte to adjacent VRAM destination address */3040WRITE_BYTE(vram, addr ^ 1, data);30413042/* Update pattern cache */3043MARK_BG_DIRTY(addr);30443045/* Increment VRAM source address */3046source++;30473048/* Increment VRAM destination address */3049addr += reg[15];3050}3051while (--length);30523053/* Update DMA source address */3054dma_src = source;3055}3056}30573058/* DMA Fill */3059static void vdp_dma_fill(unsigned int length)3060{3061/* Check destination code (CD0-CD3) */3062switch (code & 0x0F)3063{3064case 0x01: /* VRAM */3065{3066int name;30673068/* Get source data from last written FIFO entry */3069uint8 data = fifo[(fifo_idx+3)&3] >> 8;30703071do3072{3073/* Intercept writes to Sprite Attribute Table */3074if ((addr & sat_base_mask) == satb)3075{3076/* Update internal SAT */3077WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data);3078}30793080/* Write byte to adjacent VRAM address */3081WRITE_BYTE(vram, addr ^ 1, data);30823083/* Update pattern cache */3084MARK_BG_DIRTY (addr);30853086/* Increment VRAM address */3087addr += reg[15];3088}3089while (--length);3090break;3091}30923093case 0x03: /* CRAM */3094{3095/* Get source data from next available FIFO entry */3096uint16 data = fifo[fifo_idx];30973098/* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */3099data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1);31003101do3102{3103/* Pointer to CRAM 9-bit word */3104uint16 *p = (uint16 *)&cram[addr & 0x7E];31053106/* Check if CRAM data is being modified */3107if (data != *p)3108{3109/* CRAM index (64 words) */3110int index = (addr >> 1) & 0x3F;31113112/* Write CRAM data */3113*p = data;31143115/* Color entry 0 of each palette is never displayed (transparent pixel) */3116if (index & 0x0F)3117{3118/* Update color palette */3119color_update_m5(index, data);3120}31213122/* Update backdrop color */3123if (index == border)3124{3125color_update_m5(0x00, data);3126}3127}31283129/* Increment CRAM address */3130addr += reg[15];3131}3132while (--length);3133break;3134}31353136case 0x05: /* VSRAM */3137{3138/* Get source data from next available FIFO entry */3139uint16 data = fifo[fifo_idx];31403141do3142{3143/* Write VSRAM data */3144*(uint16 *)&vsram[addr & 0x7E] = data;31453146/* Increment VSRAM address */3147addr += reg[15];3148}3149while (--length);3150break;3151}31523153default:3154{3155/* invalid destination does nothing (Williams Greatest Hits after soft reset) */31563157/* address is still incremented */3158addr += reg[15] * length;3159}3160}3161}316231633164