/***************************************************************************************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 uint8 dmafill; /* DMA Fill pending flag */138static int32 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 int32 fifo_idx; /* FIFO write index */141static int32 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}429430431int vdp_context_save(uint8 *state)432{433int bufferptr = 0;434uint8 special;435436/* VDP context */437save_param(sat, sizeof(sat));438save_param(vram, sizeof(vram));439save_param(cram, sizeof(cram));440save_param(vsram, sizeof(vsram));441save_param(reg, sizeof(reg));442save_param(&hint_pending, sizeof(hint_pending));443save_param(&vint_pending, sizeof(vint_pending));444save_param(&status, sizeof(status));445save_param(&dma_length, sizeof(dma_length));446447/* Global variables */448save_param(&ntab, sizeof(ntab));449save_param(&ntbb, sizeof(ntbb));450save_param(&ntwb, sizeof(ntwb));451save_param(&satb, sizeof(satb));452save_param(&hscb, sizeof(hscb));453/*save_param(bg_name_dirty, sizeof(bg_name_dirty)); not needed */454/*save_param(bg_name_list, sizeof(bg_name_list)); not needed */455/*save_param(&bg_list_index, sizeof(bg_list_index)); not needed */456save_param(&hscroll_mask, sizeof(hscroll_mask));457save_param(&playfield_shift, sizeof(playfield_shift));458save_param(&playfield_col_mask, sizeof(playfield_col_mask));459save_param(&playfield_row_mask, sizeof(playfield_row_mask));460save_param(&vscroll, sizeof(vscroll));461save_param(&odd_frame, sizeof(odd_frame));462save_param(&im2_flag, sizeof(im2_flag));463save_param(&interlaced, sizeof(interlaced));464/*save_param(&vdp_pal, sizeof(vdp_pal)); I believe this is just set during initialization */465save_param(&v_counter, sizeof(v_counter));466save_param(&vc_max, sizeof(vc_max));467/*save_param(&lines_per_frame, sizeof(lines_per_frame)); I believe this is just set during initialization */468save_param(&max_sprite_pixels, sizeof(max_sprite_pixels));469save_param(&fifo_write_cnt, sizeof(fifo_write_cnt));470save_param(&fifo_slots, sizeof(fifo_slots));471save_param(&hvc_latch, sizeof(hvc_latch));472/*special*/473special = (hctab==cycle2hc32)?32:40;474save_param(&special, sizeof(special));475476/* other things */477save_param(&pending, sizeof(pending));478save_param(&code, sizeof(code));479save_param(&dma_type, sizeof(dma_type));480save_param(&addr, sizeof(addr));481save_param(&addr_latch, sizeof(addr_latch));482save_param(&status, sizeof(status));483save_param(&sat_base_mask, sizeof(sat_base_mask));484save_param(&sat_addr_mask, sizeof(sat_addr_mask));485save_param(&dma_src, sizeof(dma_src));486save_param(&dma_endCycles, sizeof(dma_endCycles));487save_param(&dmafill, sizeof(dmafill));488save_param(&cached_write, sizeof(cached_write));489save_param(fifo, sizeof(fifo));490save_param(&fifo_idx, sizeof(fifo_idx));491save_param(&fifo_cycles, sizeof(fifo_cycles));492493return bufferptr;494}495496int vdp_context_load(uint8 *state, uint8 version)497{498int i, bufferptr = 0;499uint8 special;500uint8 temp_reg[0x20];501502/* VDP context */503load_param(sat, sizeof(sat));504load_param(vram, sizeof(vram));505load_param(cram, sizeof(cram));506load_param(vsram, sizeof(vsram));507load_param(temp_reg, sizeof(temp_reg));508load_param(&hint_pending, sizeof(hint_pending));509load_param(&vint_pending, sizeof(vint_pending));510load_param(&status, sizeof(status));511load_param(&dma_length, sizeof(dma_length));512513/* Global variables */514load_param(&ntab, sizeof(ntab));515load_param(&ntbb, sizeof(ntbb));516load_param(&ntwb, sizeof(ntwb));517load_param(&satb, sizeof(satb));518load_param(&hscb, sizeof(hscb));519/*load_param(bg_name_dirty, sizeof(bg_name_dirty)); not needed */520/*load_param(bg_name_list, sizeof(bg_name_list)); not needed */521/*load_param(&bg_list_index, sizeof(bg_list_index)); not needed */522load_param(&hscroll_mask, sizeof(hscroll_mask));523load_param(&playfield_shift, sizeof(playfield_shift));524load_param(&playfield_col_mask, sizeof(playfield_col_mask));525load_param(&playfield_row_mask, sizeof(playfield_row_mask));526load_param(&vscroll, sizeof(vscroll));527load_param(&odd_frame, sizeof(odd_frame));528load_param(&im2_flag, sizeof(im2_flag));529load_param(&interlaced, sizeof(interlaced));530/*load_param(&vdp_pal, sizeof(vdp_pal)); I believe this is just set during initialization */531load_param(&v_counter, sizeof(v_counter));532load_param(&vc_max, sizeof(vc_max));533/*load_param(&lines_per_frame, sizeof(lines_per_frame)); I believe this is just set during initialization */534load_param(&max_sprite_pixels, sizeof(max_sprite_pixels));535load_param(&fifo_write_cnt, sizeof(fifo_write_cnt));536load_param(&fifo_slots, sizeof(fifo_slots));537load_param(&hvc_latch, sizeof(hvc_latch));538/*special*/539load_param(&special, sizeof(special));540if(special==32) hctab = cycle2hc32; else hctab = cycle2hc40;541542/* other things */543load_param(&pending, sizeof(pending));544load_param(&code, sizeof(code));545load_param(&dma_type, sizeof(dma_type));546load_param(&addr, sizeof(addr));547load_param(&addr_latch, sizeof(addr_latch));548load_param(&status, sizeof(status));549load_param(&sat_base_mask, sizeof(sat_base_mask));550load_param(&sat_addr_mask, sizeof(sat_addr_mask));551load_param(&dma_src, sizeof(dma_src));552load_param(&dma_endCycles, sizeof(dma_endCycles));553load_param(&dmafill, sizeof(dmafill));554load_param(&cached_write, sizeof(cached_write));555load_param(fifo, sizeof(fifo));556load_param(&fifo_idx, sizeof(fifo_idx));557load_param(&fifo_cycles, sizeof(fifo_cycles));558559560/* restore VDP registers */561if (system_hw < SYSTEM_MD)562{563if (system_hw > SYSTEM_SG)564{565for (i=0;i<0x10;i++)566{567pending = 1;568addr_latch = temp_reg[i];569vdp_sms_ctrl_w(0x80 | i);570}571}572else573{574for (i=0;i<0x08;i++)575{576pending = 1;577addr_latch = temp_reg[i];578vdp_tms_ctrl_w(0x80 | i);579}580}581}582else583{584for (i=0;i<0x20;i++)585{586vdp_reg_w(i, temp_reg[i], 0);587}588}589590591if (reg[1] & 0x04)592{593/* Mode 5 */594bg_list_index = 0x800;595596/* reinitialize palette */597color_update_m5(0, *(uint16 *)&cram[border << 1]);598for(i = 1; i < 0x40; i++)599{600color_update_m5(i, *(uint16 *)&cram[i << 1]);601}602}603else604{605/* Modes 0,1,2,3,4 */606bg_list_index = 0x200;607608/* reinitialize palette */609for(i = 0; i < 0x20; i ++)610{611color_update_m4(i, *(uint16 *)&cram[i << 1]);612}613color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);614}615616/* invalidate cache */617for (i=0;i<bg_list_index;i++)618{619bg_name_list[i]=i;620bg_name_dirty[i]=0xFF;621}622623return bufferptr;624}625626627628/*--------------------------------------------------------------------------*/629/* DMA update function (Mega Drive VDP only) */630/*--------------------------------------------------------------------------*/631632void vdp_dma_update(unsigned int cycles)633{634int dma_cycles, dma_bytes;635636/* DMA transfer rate (bytes per line)637638According to the manual, here's a table that describes the transfer639rates of each of the three DMA types:640641DMA Mode Width Display Transfer Count642-----------------------------------------------------64368K > VDP 32-cell Active 16644Blanking 16764540-cell Active 18646Blanking 205647VRAM Fill 32-cell Active 15648Blanking 16664940-cell Active 17650Blanking 204651VRAM Copy 32-cell Active 8652Blanking 8365340-cell Active 9654Blanking 102655656'Active' is the active display period, 'Blanking' is either the vertical657blanking period or when the display is forcibly blanked via register #1.658659The above transfer counts are all in bytes, unless the destination is660CRAM or VSRAM for a 68K > VDP transfer, in which case it is in words.661*/662unsigned int rate = dma_timing[(status & 8) || !(reg[1] & 0x40)][reg[12] & 1];663664/* Adjust for 68k bus DMA to VRAM (one word = 2 access) or DMA Copy (one read + one write = 2 access) */665rate = rate >> (dma_type & 1);666667/* Remaining DMA cycles */668if (status & 8)669{670/* Process DMA until the end of VBLANK */671/* NOTE: DMA timings can not change during VBLANK because active display width cannot be modified. */672/* Indeed, writing VDP registers during DMA is either impossible (when doing DMA from 68k bus, CPU */673/* is locked) or will abort DMA operation (in case of DMA Fill or Copy). */674dma_cycles = (lines_per_frame * MCYCLES_PER_LINE) - cycles;675}676else677{678/* Process DMA until the end of current line */679dma_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - cycles;680}681682/* Remaining DMA bytes for that line */683dma_bytes = (dma_cycles * rate) / MCYCLES_PER_LINE;684685#ifdef LOGVDP686error("[%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));687#endif688689/* Check if DMA can be finished before the end of current line */690if (dma_length < dma_bytes)691{692/* Adjust remaining DMA bytes */693dma_bytes = dma_length;694dma_cycles = (dma_bytes * MCYCLES_PER_LINE) / rate;695}696697/* Update DMA timings */698if (dma_type < 2)699{700/* 68K is frozen during DMA from 68k bus */701m68k.cycles = cycles + dma_cycles;702#ifdef LOGVDP703error("-->CPU frozen for %d cycles\n", dma_cycles);704#endif705}706else707{708/* Set DMA Busy flag */709status |= 0x02;710711/* 68K is still running, set DMA end cycle */712dma_endCycles = cycles + dma_cycles;713#ifdef LOGVDP714error("-->DMA ends in %d cycles\n", dma_cycles);715#endif716}717718/* Process DMA */719if (dma_bytes > 0)720{721/* Update DMA length */722dma_length -= dma_bytes;723724/* Process DMA operation */725dma_func[reg[23] >> 4](dma_bytes);726727/* Check if DMA is finished */728if (!dma_length)729{730/* DMA source address registers are incremented during DMA (even DMA Fill) */731uint16 end = reg[21] + (reg[22] << 8) + reg[19] + (reg[20] << 8);732reg[21] = end & 0xff;733reg[22] = end >> 8;734735/* DMA length registers are decremented during DMA */736reg[19] = reg[20] = 0;737738/* perform cached write, if any */739if (cached_write >= 0)740{741vdp_68k_ctrl_w(cached_write);742cached_write = -1;743}744}745}746}747748749/*--------------------------------------------------------------------------*/750/* Control port access functions */751/*--------------------------------------------------------------------------*/752753void vdp_68k_ctrl_w(unsigned int data)754{755/* Check pending flag */756if (pending == 0)757{758/* A single long word write instruction could have started DMA with the first word */759if (dma_length)760{761/* 68k is frozen during 68k bus DMA */762/* Second word should be written after DMA completion */763/* See Formula One & Kawasaki Superbike Challenge */764if (dma_type < 2)765{766/* Latch second control word for later */767cached_write = data;768return;769}770}771772/* Check CD0-CD1 bits */773if ((data & 0xC000) == 0x8000)774{775/* VDP register write */776vdp_reg_w((data >> 8) & 0x1F, data & 0xFF, m68k.cycles);777}778else779{780/* Set pending flag (Mode 5 only) */781pending = reg[1] & 4;782}783784/* Update address and code registers */785addr = addr_latch | (data & 0x3FFF);786code = ((code & 0x3C) | ((data >> 14) & 0x03));787}788else789{790/* Clear pending flag */791pending = 0;792793/* Save address bits A15 and A14 */794addr_latch = (data & 3) << 14;795796/* Update address and code registers */797addr = addr_latch | (addr & 0x3FFF);798code = ((code & 0x03) | ((data >> 2) & 0x3C));799800/* Detect DMA operation (CD5 bit set) */801if (code & 0x20)802{803/* DMA must be enabled */804if (reg[1] & 0x10)805{806/* DMA type */807switch (reg[23] >> 6)808{809case 2:810{811/* DMA Fill */812dma_type = 2;813814/* DMA is pending until next DATA port write */815dmafill = 1;816817/* Set DMA Busy flag */818status |= 0x02;819820/* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */821dma_endCycles = 0xffffffff;822break;823}824825case 3:826{827/* DMA Copy */828dma_type = 3;829830/* DMA length */831dma_length = (reg[20] << 8) | reg[19];832833/* Zero DMA length (pre-decrementing counter) */834if (!dma_length)835{836dma_length = 0x10000;837}838839/* DMA source address */840dma_src = (reg[22] << 8) | reg[21];841842/* Trigger DMA */843vdp_dma_update(m68k.cycles);844break;845}846847default:848{849/* DMA from 68k bus */850dma_type = (code & 0x06) ? 0 : 1;851852/* DMA length */853dma_length = (reg[20] << 8) | reg[19];854855/* Zero DMA length (pre-decrementing counter) */856if (!dma_length)857{858dma_length = 0x10000;859}860861/* DMA source address */862dma_src = (reg[22] << 8) | reg[21];863864/* Transfer from SVP ROM/RAM ($000000-$3fffff) or CD Word-RAM ($200000-$3fffff/$600000-$7fffff) */865if (((system_hw == SYSTEM_MCD) && ((reg[23] & 0x70) == ((scd.cartridge.boot >> 1) + 0x10))) || (svp && !(reg[23] & 0x60)))866{867/* source data is available with one cycle delay, i.e first word written by VDP is */868/* previous data being held on 68k bus at that time, then source words are written */869/* normally to VDP RAM, with only last source word being ignored */870addr += reg[15];871dma_length--;872}873874/* Trigger DMA */875vdp_dma_update(m68k.cycles);876break;877}878}879}880}881}882883/*884FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace)885--------------------------------------------------------------------------886Each VRAM access is byte wide, so one VRAM write (word) need two slot access.887888NOTE: Invalid code 0x02 (register write) should not behave the same as VRAM889access, i.e data is ignored and only one access slot is used for each word,890BUT a few games ("Clue", "Microcosm") which accidentally corrupt code value891will have issues when emulating FIFO timings. They likely work fine on real892hardware because of periodical 68k wait-states which have been observed and893would naturaly add some delay between writes. Until those wait-states are894accurately measured and emulated, delay is forced when invalid code value895is being used.896*/897fifo_byte_access = ((code & 0x0F) <= 0x02);898}899900/* Mega Drive VDP control port specific (MS compatibility mode) */901void vdp_z80_ctrl_w(unsigned int data)902{903switch (pending)904{905case 0:906{907/* Latch LSB */908addr_latch = data;909910/* Set LSB pending flag */911pending = 1;912return;913}914915case 1:916{917/* Update address and code registers */918addr = (addr & 0xC000) | ((data & 0x3F) << 8) | addr_latch ;919code = ((code & 0x3C) | ((data >> 6) & 0x03));920921if ((code & 0x03) == 0x02)922{923/* VDP register write */924vdp_reg_w(data & 0x1F, addr_latch, Z80.cycles);925926/* Clear pending flag */927pending = 0;928return;929}930931/* Set Mode 5 pending flag */932pending = (reg[1] & 4) >> 1;933934if (!pending && !(code & 0x03))935{936/* Process VRAM read */937fifo[0] = vram[addr & 0x3FFF];938939/* Increment address register */940addr += (reg[15] + 1);941}942return;943}944945case 2:946{947/* Latch LSB */948addr_latch = data;949950/* Set LSB pending flag */951pending = 3;952return;953}954955case 3:956{957/* Clear pending flag */958pending = 0;959960/* Update address and code registers */961addr = ((addr_latch & 3) << 14) | (addr & 0x3FFF);962code = ((code & 0x03) | ((addr_latch >> 2) & 0x3C));963964/* Detect DMA operation (CD5 bit set) */965if (code & 0x20)966{967/* DMA should be enabled */968if (reg[1] & 0x10)969{970/* DMA type */971switch (reg[23] >> 6)972{973case 2:974{975/* DMA Fill will be triggered by next write to DATA port */976dmafill = 1;977978/* Set DMA Busy flag */979status |= 0x02;980981/* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */982dma_endCycles = 0xffffffff;983break;984}985986case 3:987{988/* DMA copy */989dma_type = 3;990991/* DMA length */992dma_length = (reg[20] << 8) | reg[19];993994/* Zero DMA length (pre-decrementing counter) */995if (!dma_length)996{997dma_length = 0x10000;998}9991000/* DMA source address */1001dma_src = (reg[22] << 8) | reg[21];10021003/* Trigger DMA */1004vdp_dma_update(Z80.cycles);1005break;1006}10071008default:1009{1010/* DMA from 68k bus does not work when Z80 is in control */1011break;1012}1013}1014}1015}1016}1017return;1018}1019}10201021/* Master System & Game Gear VDP control port specific */1022void vdp_sms_ctrl_w(unsigned int data)1023{1024if(pending == 0)1025{1026/* Update address register LSB */1027addr = (addr & 0x3F00) | (data & 0xFF);10281029/* Latch LSB */1030addr_latch = data;10311032/* Set LSB pending flag */1033pending = 1;1034}1035else1036{1037/* Update address and code registers */1038code = (data >> 6) & 3;1039addr = (data << 8 | addr_latch) & 0x3FFF;10401041/* Clear pending flag */1042pending = 0;10431044if (code == 0)1045{1046/* Process VRAM read */1047fifo[0] = vram[addr & 0x3FFF];10481049/* Increment address register */1050addr = (addr + 1) & 0x3FFF;1051return;1052}10531054if (code == 2)1055{1056/* Save current VDP mode */1057int mode, prev = (reg[0] & 0x06) | (reg[1] & 0x18);10581059/* Write VDP register 0-15 */1060vdp_reg_w(data & 0x0F, addr_latch, Z80.cycles);10611062/* Check VDP mode changes */1063mode = (reg[0] & 0x06) | (reg[1] & 0x18);1064prev ^= mode;10651066if (prev)1067{1068/* Check for extended modes */1069if (system_hw > SYSTEM_SMS)1070{1071int height;10721073if (mode == 0x0E) /* M1=0,M2=1,M3=1,M4=1 */1074{1075/* Mode 4 extended (240 lines) */1076height = 240;10771078/* Update vertical counter max value */1079vc_max = vc_table[3][vdp_pal];1080}1081else if (mode == 0x16) /* M1=1,M2=1,M3=0,M4=1 */1082{1083/* Mode 4 extended (224 lines) */1084height = 224;10851086/* Update vertical counter max value */1087vc_max = vc_table[1][vdp_pal];1088}1089else1090{1091/* Mode 4 default (224 lines) */1092height = 192;10931094/* Default vertical counter max value */1095vc_max = vc_table[0][vdp_pal];1096}10971098if (height != bitmap.viewport.h)1099{1100if (status & 8)1101{1102/* viewport changes should be applied on next frame */1103bitmap.viewport.changed |= 2;1104}1105else1106{1107/* update active display */1108bitmap.viewport.h = height;11091110/* update vertical overscan */1111if (config.overscan & 1)1112{1113bitmap.viewport.y = (240 + 48*vdp_pal - height) >> 1;1114}1115else1116{1117if ((system_hw == SYSTEM_GG) && !config.gg_extra)1118{1119/* Display area reduced to 160x144 */1120bitmap.viewport.y = (144 - height) / 2;1121}1122else1123{1124bitmap.viewport.y = 0;1125}1126}1127}1128}1129}11301131/* Rendering mode */1132switch (mode)1133{1134case 0x00: /* Graphics I */1135{1136render_bg = render_bg_m0;1137break;1138}11391140case 0x10: /* Text */1141{1142render_bg = render_bg_m1;1143break;1144}11451146case 0x02: /* Graphics II */1147{1148render_bg = render_bg_m2;1149break;1150}11511152case 0x12: /* Text (Extended PG) */1153{1154render_bg = render_bg_m1x;1155break;1156}11571158case 0x08: /* Multicolor */1159{1160render_bg = render_bg_m3;1161break;1162}11631164case 0x18: /* Invalid (1+3) */1165{1166render_bg = render_bg_inv;1167break;1168}11691170case 0x0A: /* Multicolor (Extended PG) */1171{1172render_bg = render_bg_m3x;1173break;1174}11751176case 0x1A: /* Invalid (1+2+3) */1177{1178render_bg = render_bg_inv;1179break;1180}11811182default: /* Mode 4 */1183{1184render_bg = render_bg_m4;1185break;1186}1187}11881189/* Mode switching */1190if (prev & 0x04)1191{1192int i;11931194if (mode & 0x04)1195{1196/* Mode 4 sprites */1197parse_satb = parse_satb_m4;1198render_obj = render_obj_m4;11991200/* force BG cache update*/1201bg_list_index = 0x200;1202}1203else1204{1205/* TMS-mode sprites */1206parse_satb = parse_satb_tms;1207render_obj = render_obj_tms;12081209/* BG cache is not used */1210bg_list_index = 0;1211}12121213/* reinitialize palette */1214for(i = 0; i < 0x20; i ++)1215{1216color_update_m4(i, *(uint16 *)&cram[i << 1]);1217}1218color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);1219}1220}1221}1222}1223}12241225/* SG-1000 VDP (TMS99xx) control port specific */1226void vdp_tms_ctrl_w(unsigned int data)1227{1228if(pending == 0)1229{1230/* Latch LSB */1231addr_latch = data;12321233/* Set LSB pending flag */1234pending = 1;1235}1236else1237{1238/* Update address and code registers */1239code = (data >> 6) & 3;1240addr = (data << 8 | addr_latch) & 0x3FFF;12411242/* Clear pending flag */1243pending = 0;12441245if (code == 0)1246{1247/* Process VRAM read */1248fifo[0] = vram[addr & 0x3FFF];12491250/* Increment address register */1251addr = (addr + 1) & 0x3FFF;1252return;1253}12541255if (code & 2)1256{1257/* VDP register index (0-7) */1258data &= 0x07;12591260/* Write VDP register */1261vdp_reg_w(data, addr_latch, Z80.cycles);12621263/* Check VDP mode changes */1264if (data < 2)1265{1266int mode = (reg[0] & 0x02) | (reg[1] & 0x18);12671268/* Rendering mode */1269switch (mode)1270{1271case 0x00: /* Graphics I */1272{1273render_bg = render_bg_m0;1274break;1275}12761277case 0x10: /* Text */1278{1279render_bg = render_bg_m1;1280break;1281}12821283case 0x02: /* Graphics II */1284{1285render_bg = render_bg_m2;1286break;1287}12881289case 0x12: /* Text (Extended PG) */1290{1291render_bg = render_bg_m1x;1292break;1293}12941295case 0x08: /* Multicolor */1296{1297render_bg = render_bg_m3;1298break;1299}13001301case 0x18: /* Invalid (1+3) */1302{1303render_bg = render_bg_inv;1304break;1305}13061307case 0x0A: /* Multicolor (Extended PG) */1308{1309render_bg = render_bg_m3x;1310break;1311}13121313case 0x1A: /* Invalid (1+2+3) */1314{1315render_bg = render_bg_inv;1316break;1317}1318}1319}1320}1321}1322}13231324/*1325* Status register1326*1327* Bits1328* 0 NTSC(0)/PAL(1)1329* 1 DMA Busy1330* 2 During HBlank1331* 3 During VBlank1332* 4 0:1 even:odd field (interlaced modes only)1333* 5 Sprite collision1334* 6 Too many sprites per line1335* 7 v interrupt occurred1336* 8 Write FIFO full1337* 9 Write FIFO empty1338* 10 - 15 Open Bus1339*/1340unsigned int vdp_68k_ctrl_r(unsigned int cycles)1341{1342unsigned int temp;13431344/* Update FIFO status flags if not empty */1345if (fifo_write_cnt)1346{1347vdp_fifo_update(cycles);1348}13491350/* Check if DMA Busy flag is set */1351if (status & 2)1352{1353/* Check if DMA is finished */1354if (!dma_length && (cycles >= dma_endCycles))1355{1356/* Clear DMA Busy flag */1357status &= 0xFFFD;1358}1359}13601361/* Return VDP status */1362temp = status;13631364/* Clear pending flag */1365pending = 0;13661367/* Clear SOVR & SCOL flags */1368status &= 0xFF9F;13691370/* Display OFF: VBLANK flag is set */1371if (!(reg[1] & 0x40))1372{1373temp |= 0x08;1374}13751376/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican, V.R Troopers, Gouketsuji Ichizoku,...) */1377/* NB: this is not 100% accurate and need to be verified on real hardware */1378if ((cycles % MCYCLES_PER_LINE) < 588)1379{1380temp |= 0x04;1381}13821383#ifdef LOGVDP1384error("[%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));1385#endif1386return (temp);1387}13881389unsigned int vdp_z80_ctrl_r(unsigned int cycles)1390{1391unsigned int temp;13921393/* Cycle-accurate SOVR & VINT flags */1394int line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;13951396/* Check if DMA busy flag is set (Mega Drive VDP specific) */1397if (status & 2)1398{1399/* Check if DMA is finished */1400if (!dma_length && (cycles >= dma_endCycles))1401{1402/* Clear DMA Busy flag */1403status &= 0xFD;1404}1405}14061407/* Check if we are already on next line */1408if (line > v_counter)1409{1410v_counter = line;1411if (line == (bitmap.viewport.h + 1))1412{1413/* set VINT flag (immediately cleared after) */1414status |= 0x80;1415}1416else if ((line >= 0) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))1417{1418/* render next line to check sprites overflow & collision */1419render_line(line);1420}1421}14221423/* Return VDP status */1424temp = status;14251426/* Clear pending flag */1427pending = 0;14281429/* Clear VINT, SOVR & SCOL flags */1430status &= 0xFF1F;14311432/* Mega Drive VDP specific */1433if (system_hw & SYSTEM_MD)1434{1435/* Display OFF: VBLANK flag is set */1436if (!(reg[1] & 0x40))1437{1438temp |= 0x08;1439}14401441/* HBLANK flag */1442if ((cycles % MCYCLES_PER_LINE) < 588)1443{1444temp |= 0x04;1445}1446}1447else if (reg[0] & 0x04)1448{1449/* Mode 4 unused bits (fixes PGA Tour Golf) */1450temp |= 0x1F;1451}14521453/* Cycle-accurate SCOL flag */1454if ((temp & 0x20) && (line == (spr_col >> 8)))1455{1456if (system_hw & SYSTEM_MD)1457{1458/* COL flag is set at HCount 0xFF on MD */1459if ((cycles % MCYCLES_PER_LINE) < 105)1460{1461status |= 0x20;1462temp &= ~0x20;1463}1464}1465else1466{1467/* COL flag is set at the pixel it occurs */1468uint8 hc = hctab[(cycles + SMS_CYCLE_OFFSET + 15) % MCYCLES_PER_LINE];1469if ((hc < (spr_col & 0xff)) || (hc > 0xf3))1470{1471status |= 0x20;1472temp &= ~0x20;1473}1474}1475}14761477/* Clear HINT & VINT pending flags */1478hint_pending = vint_pending = 0;14791480/* Clear Z80 interrupt */1481Z80.irq_state = CLEAR_LINE;14821483#ifdef LOGVDP1484error("[%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);1485#endif1486return (temp);1487}14881489/*--------------------------------------------------------------------------*/1490/* HV Counters */1491/*--------------------------------------------------------------------------*/14921493unsigned int vdp_hvc_r(unsigned int cycles)1494{1495int vc;1496unsigned int data = hvc_latch;14971498/* Check if HVC latch is enabled */1499if (data)1500{1501/* Mode 5: HV-counters are frozen (cf. lightgun games, Sunset Riders logo) */1502if (reg[1] & 0x04)1503{1504#ifdef LOGVDP1505error("[%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));1506#endif1507/* return latched HVC value */1508return (data & 0xffff);1509}1510else1511{1512/* Mode 4: by default, V-counter runs normally & H counter is frozen */1513data &= 0xff;1514}1515}1516else1517{1518/* Cycle-accurate H-Counter (Striker, Mickey Mania, Skitchin, Road Rash I,II,III, Sonic 3D Blast...) */1519data = hctab[cycles % MCYCLES_PER_LINE];1520}15211522/* Cycle-accurate V-Counter (cycle counter starts from line -1) */1523vc = (cycles / MCYCLES_PER_LINE) - 1;15241525/* V-Counter overflow */1526if (vc > vc_max)1527{1528vc -= lines_per_frame;1529}15301531/* Interlaced modes */1532if (interlaced)1533{1534/* Interlace mode 2 (Sonic the Hedgehog 2, Combat Cars) */1535vc <<= im2_flag;15361537/* Replace bit 0 with bit 8 */1538vc = (vc & ~1) | ((vc >> 8) & 1);1539}15401541/* return H-Counter in LSB & V-Counter in MSB */1542data |= ((vc & 0xff) << 8);15431544#ifdef LOGVDP1545error("[%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));1546#endif1547return (data);1548}154915501551/*--------------------------------------------------------------------------*/1552/* Test registers */1553/*--------------------------------------------------------------------------*/15541555void vdp_test_w(unsigned int data)1556{1557#ifdef LOGERROR1558error("Unused VDP Write 0x%x (%08x)\n", data, m68k_get_reg(M68K_REG_PC));1559#endif1560}156115621563/*--------------------------------------------------------------------------*/1564/* 68k interrupt handler (TODO: check how interrupts are handled in Mode 4) */1565/*--------------------------------------------------------------------------*/15661567int vdp_68k_irq_ack(int int_level)1568{1569#ifdef LOGVDP1570error("[%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));1571#endif15721573/* VINT has higher priority (Fatal Rewind) */1574if (vint_pending & reg[1])1575{1576#ifdef LOGVDP1577error("---> VINT cleared\n");1578#endif15791580/* Clear VINT pending flag */1581vint_pending = 0;1582status &= ~0x80;15831584/* Update IRQ status */1585if (hint_pending & reg[0])1586{1587m68k_set_irq(4);1588}1589else1590{1591m68k_set_irq(0);1592}1593}1594else1595{1596#ifdef LOGVDP1597error("---> HINT cleared\n");1598#endif15991600/* Clear HINT pending flag */1601hint_pending = 0;16021603/* Update IRQ status */1604m68k_set_irq(0);1605}16061607return M68K_INT_ACK_AUTOVECTOR;1608}160916101611/*--------------------------------------------------------------------------*/1612/* VDP registers update function */1613/*--------------------------------------------------------------------------*/16141615static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles)1616{1617#ifdef LOGVDP1618error("[%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));1619#endif16201621/* VDP registers #11 to #23 cannot be updated in Mode 4 (Captain Planet & Avengers, Bass Master Classic Pro Edition) */1622if (!(reg[1] & 4) && (r > 10))1623{1624return;1625}16261627switch(r)1628{1629case 0: /* CTRL #1 */1630{1631/* Look for changed bits */1632r = d ^ reg[0];1633reg[0] = d;16341635/* Line Interrupt */1636if ((r & 0x10) && hint_pending)1637{1638/* Update IRQ status */1639if (vint_pending & reg[1])1640{1641set_irq_line(6);1642}1643else if (d & 0x10)1644{1645set_irq_line_delay(4);1646}1647else1648{1649set_irq_line(0);1650}1651}16521653/* Palette selection */1654if (r & 0x04)1655{1656/* Mega Drive VDP only */1657if (system_hw & SYSTEM_MD)1658{1659/* Reset color palette */1660int i;1661if (reg[1] & 0x04)1662{1663/* Mode 5 */1664color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1665for (i = 1; i < 0x40; i++)1666{1667color_update_m5(i, *(uint16 *)&cram[i << 1]);1668}1669}1670else1671{1672/* Mode 4 */1673for (i = 0; i < 0x20; i++)1674{1675color_update_m4(i, *(uint16 *)&cram[i << 1]);1676}1677color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);1678}1679}1680}16811682/* HVC latch (Sunset Riders, Lightgun games) */1683if (r & 0x02)1684{1685/* Mega Drive VDP only */1686if (system_hw & SYSTEM_MD)1687{1688/* Mode 5 only */1689if (reg[1] & 0x04)1690{1691if (d & 0x02)1692{1693/* Latch current HVC */1694hvc_latch = vdp_hvc_r(cycles) | 0x10000;1695}1696else1697{1698/* Free-running HVC */1699hvc_latch = 0;1700}1701}1702}1703}1704break;1705}17061707case 1: /* CTRL #2 */1708{1709/* Look for changed bits */1710r = d ^ reg[1];1711reg[1] = d;17121713/* Display status (modified during active display) */1714if ((r & 0x40) && (v_counter < bitmap.viewport.h))1715{1716/* Cycle offset vs HBLANK */1717int offset = cycles - mcycles_vdp;1718if (offset <= 860)1719{1720/* Sprite rendering is limited if display was disabled during HBLANK (Mickey Mania 3d level, Overdrive Demo) */1721if (d & 0x40)1722{1723/* NB: This is not 100% accurate. On real hardware, the maximal number of rendered sprites pixels */1724/* for the current line (normally 256 or 320 pixels) but also the maximal number of pre-processed */1725/* sprites for the next line (normally 64 or 80 sprites) are both reduced depending on the amount */1726/* of cycles spent with display disabled. Here we only reduce them by a fixed amount when display */1727/* has been reenabled after a specific point within HBLANK. */1728if (offset > 360)1729{1730max_sprite_pixels = 128;1731}1732}17331734/* Redraw entire line (Legend of Galahad, Lemmings 2, Formula One, Kawasaki Super Bike, Deadly Moves,...) */1735render_line(v_counter);17361737/* Restore default */1738max_sprite_pixels = 256 + ((reg[12] & 1) << 6);1739}1740else if (system_hw & SYSTEM_MD)1741{1742/* Active pixel offset */1743if (reg[12] & 1)1744{1745/* dot clock = MCLK / 8 */1746offset = ((offset - 860) / 8) + 16;1747}1748else1749{1750/* dot clock = MCLK / 10 */1751offset = ((offset - 860) / 10) + 16;1752}17531754/* Line is partially blanked (Nigel Mansell's World Championship Racing , Ren & Stimpy Show, ...) */1755if (offset < bitmap.viewport.w)1756{1757if (d & 0x40)1758{1759render_line(v_counter);1760blank_line(v_counter, 0, offset);1761}1762else1763{1764blank_line(v_counter, offset, bitmap.viewport.w - offset);1765}1766}1767}1768}17691770/* Frame Interrupt */1771if ((r & 0x20) && vint_pending)1772{1773/* Update IRQ status */1774if (d & 0x20)1775{1776set_irq_line_delay(6);1777}1778else if (hint_pending & reg[0])1779{1780set_irq_line(4);1781}1782else1783{1784set_irq_line(0);1785}1786}17871788/* Active display height */1789if (r & 0x08)1790{1791/* Mega Drive VDP only */1792if (system_hw & SYSTEM_MD)1793{1794/* Mode 5 only */1795if (d & 0x04)1796{1797/* Changes should be applied on next frame */1798bitmap.viewport.changed |= 2;17991800/* Update vertical counter max value */1801vc_max = vc_table[(d >> 2) & 3][vdp_pal];1802}1803}1804}18051806/* Rendering mode */1807if (r & 0x04)1808{1809/* Mega Drive VDP only */1810if (system_hw & SYSTEM_MD)1811{1812int i;1813if (d & 0x04)1814{1815/* Mode 5 rendering */1816parse_satb = parse_satb_m5;1817update_bg_pattern_cache = update_bg_pattern_cache_m5;1818if (im2_flag)1819{1820render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;1821render_obj = (reg[12] & 0x08) ? render_obj_m5_im2_ste : render_obj_m5_im2;1822}1823else1824{1825render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;1826render_obj = (reg[12] & 0x08) ? render_obj_m5_ste : render_obj_m5;1827}18281829/* Reset color palette */1830color_update_m5(0x00, *(uint16 *)&cram[border << 1]);1831for (i = 1; i < 0x40; i++)1832{1833color_update_m5(i, *(uint16 *)&cram[i << 1]);1834}18351836/* Mode 5 bus access */1837vdp_68k_data_w = vdp_68k_data_w_m5;1838vdp_z80_data_w = vdp_z80_data_w_m5;1839vdp_68k_data_r = vdp_68k_data_r_m5;1840vdp_z80_data_r = vdp_z80_data_r_m5;18411842/* Change display height */1843if (status & 8)1844{1845/* viewport changes should be applied on next frame */1846bitmap.viewport.changed |= 2;1847}1848else1849{1850/* Update current frame active display height */1851bitmap.viewport.h = 224 + ((d & 8) << 1);1852bitmap.viewport.y = (config.overscan & 1) * (8 - (d & 8) + 24*vdp_pal);1853}18541855/* Clear HVC latched value */1856hvc_latch = 0;18571858/* Check if HVC latch bit is set */1859if (reg[0] & 0x02)1860{1861/* Latch current HVC */1862hvc_latch = vdp_hvc_r(cycles) | 0x10000;1863}18641865/* max tiles to invalidate */1866bg_list_index = 0x800;1867}1868else1869{1870/* Mode 4 rendering */1871parse_satb = parse_satb_m4;1872update_bg_pattern_cache = update_bg_pattern_cache_m4;1873render_bg = render_bg_m4;1874render_obj = render_obj_m4;18751876/* Reset color palette */1877for (i = 0; i < 0x20; i++)1878{1879color_update_m4(i, *(uint16 *)&cram[i << 1]);1880}1881color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (border & 0x0F)) << 1]);18821883/* Mode 4 bus access */1884vdp_68k_data_w = vdp_68k_data_w_m4;1885vdp_z80_data_w = vdp_z80_data_w_m4;1886vdp_68k_data_r = vdp_68k_data_r_m4;1887vdp_z80_data_r = vdp_z80_data_r_m4;18881889if (status & 8)1890{1891/* viewport changes should be applied on next frame */1892bitmap.viewport.changed |= 2;1893}1894else1895{1896/* Update current frame active display */1897bitmap.viewport.h = 192;1898bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);1899}19001901/* Latch current HVC */1902hvc_latch = vdp_hvc_r(cycles) | 0x10000;19031904/* max tiles to invalidate */1905bg_list_index = 0x200;1906}19071908/* Invalidate pattern cache */1909for (i=0;i<bg_list_index;i++)1910{1911bg_name_list[i] = i;1912bg_name_dirty[i] = 0xFF;1913}19141915/* Update vertical counter max value */1916vc_max = vc_table[(d >> 2) & 3][vdp_pal];1917}1918else1919{1920/* No effect (cleared to avoid mode 5 detection elsewhere) */1921reg[1] &= ~0x04;1922}1923}1924break;1925}19261927case 2: /* Plane A Name Table Base */1928{1929reg[2] = d;1930ntab = (d << 10) & 0xE000;19311932/* Plane A Name Table Base changed during HBLANK */1933if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1934{1935/* render entire line */1936render_line(v_counter);1937}1938break;1939}19401941case 3: /* Window Plane Name Table Base */1942{1943reg[3] = d;1944if (reg[12] & 0x01)1945{1946ntwb = (d << 10) & 0xF000;1947}1948else1949{1950ntwb = (d << 10) & 0xF800;1951}19521953/* Window Plane Name Table Base changed during HBLANK */1954if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1955{1956/* render entire line */1957render_line(v_counter);1958}1959break;1960}19611962case 4: /* Plane B Name Table Base */1963{1964reg[4] = d;1965ntbb = (d << 13) & 0xE000;19661967/* Plane B Name Table Base changed during HBLANK (Adventures of Batman & Robin) */1968if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (cycles <= (mcycles_vdp + 860)))1969{1970/* render entire line */1971render_line(v_counter);1972}19731974break;1975}19761977case 5: /* Sprite Attribute Table Base */1978{1979reg[5] = d;1980satb = (d << 9) & sat_base_mask;1981break;1982}19831984case 7: /* Backdrop color */1985{1986reg[7] = d;19871988/* Check if backdrop color changed */1989d &= 0x3F;19901991if (d != border)1992{1993/* Update backdrop color */1994border = d;19951996/* Reset palette entry */1997if (reg[1] & 4)1998{1999/* Mode 5 */2000color_update_m5(0x00, *(uint16 *)&cram[d << 1]);2001}2002else2003{2004/* Mode 4 */2005color_update_m4(0x40, *(uint16 *)&cram[(0x10 | (d & 0x0F)) << 1]);2006}20072008/* Backdrop color modified during HBLANK (Road Rash 1,2,3)*/2009if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))2010{2011/* remap entire line */2012remap_line(v_counter);2013}2014}2015break;2016}20172018case 8: /* Horizontal Scroll (Mode 4 only) */2019{2020int line;20212022/* Hscroll is latched at HCount 0xF3, HCount 0xF6 on MD */2023/* Line starts at HCount 0xF4, HCount 0xF6 on MD */2024if (system_hw < SYSTEM_MD)2025{2026cycles = cycles + 15;2027}20282029/* Make sure Hscroll has not already been latched */2030line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2031if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2032{2033v_counter = line;2034render_line(line);2035}20362037reg[8] = d;2038break;2039}20402041case 11: /* CTRL #3 */2042{2043reg[11] = d;20442045/* Horizontal scrolling mode */2046hscroll_mask = hscroll_mask_table[d & 0x03];20472048/* Vertical Scrolling mode */2049if (d & 0x04)2050{2051render_bg = im2_flag ? render_bg_m5_im2_vs : render_bg_m5_vs;2052}2053else2054{2055render_bg = im2_flag ? render_bg_m5_im2 : render_bg_m5;2056}2057break;2058}20592060case 12: /* CTRL #4 */2061{2062/* Look for changed bits */2063r = d ^ reg[12];2064reg[12] = d;20652066/* Shadow & Highlight mode */2067if (r & 0x08)2068{2069/* Reset color palette */2070int i;2071color_update_m5(0x00, *(uint16 *)&cram[border << 1]);2072for (i = 1; i < 0x40; i++)2073{2074color_update_m5(i, *(uint16 *)&cram[i << 1]);2075}20762077/* Update sprite rendering function */2078if (d & 0x08)2079{2080render_obj = im2_flag ? render_obj_m5_im2_ste : render_obj_m5_ste;2081}2082else2083{2084render_obj = im2_flag ? render_obj_m5_im2 : render_obj_m5;2085}2086}20872088/* Interlaced modes */2089if (r & 0x06)2090{2091/* changes should be applied on next frame */2092bitmap.viewport.changed |= 2;2093}20942095/* Active display width */2096if (r & 0x01)2097{2098if (d & 0x01)2099{2100/* Update display-dependant registers */2101ntwb = (reg[3] << 10) & 0xF000;2102satb = (reg[5] << 9) & 0xFC00;2103sat_base_mask = 0xFC00;2104sat_addr_mask = 0x03FF;21052106/* Update HC table */2107hctab = cycle2hc40;21082109/* Update clipping */2110window_clip(reg[17], 1);21112112/* Max. sprite pixels per line */2113max_sprite_pixels = 320;2114}2115else2116{2117/* Update display-dependant registers */2118ntwb = (reg[3] << 10) & 0xF800;2119satb = (reg[5] << 9) & 0xFE00;2120sat_base_mask = 0xFE00;2121sat_addr_mask = 0x01FF;21222123/* Update HC table */2124hctab = cycle2hc32;21252126/* Update clipping */2127window_clip(reg[17], 0);21282129/* Max. sprite pixels per line */2130max_sprite_pixels = 256;2131}21322133/* Active display width modified during HBLANK (Bugs Bunny Double Trouble) */2134if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860)))2135{2136/* Update active display width */2137bitmap.viewport.w = 256 + ((d & 1) << 6);21382139/* Redraw entire line */2140render_line(v_counter);2141}2142else if (v_counter == (lines_per_frame - 1))2143{2144/* Update starting frame active display width */2145bitmap.viewport.w = 256 + ((d & 1) << 6);2146}2147else2148{2149/* Changes should be applied on next frame (Golden Axe III intro) */2150/* NB: not 100% accurate but required since backend framebuffer width cannot be modified mid-frame. */2151/* This would require a fixed framebuffer width (based on TV screen aspect ratio) and pixel scaling */2152/* to be done during rendering (depending on active display pixel aspect ratio in H32 or H40 mode). */2153/* Display is generally disabled when this is modified so it shouldn't be really noticeable anyway. */2154bitmap.viewport.changed |= 2;2155}2156}2157break;2158}21592160case 13: /* HScroll Base Address */2161{2162reg[13] = d;2163hscb = (d << 10) & 0xFC00;2164break;2165}21662167case 16: /* Playfield size */2168{2169reg[16] = d;2170playfield_shift = shift_table[(d & 3)];2171playfield_col_mask = col_mask_table[(d & 3)];2172playfield_row_mask = row_mask_table[(d >> 4) & 3];2173break;2174}21752176case 17: /* Window/Plane A vertical clipping */2177{2178reg[17] = d;2179window_clip(d, reg[12] & 1);2180break;2181}21822183default:2184{2185reg[r] = d;2186break;2187}2188}2189}21902191/*--------------------------------------------------------------------------*/2192/* FIFO emulation (Mega Drive VDP specific) */2193/* ---------------------------------------- */2194/* */2195/* CPU access to VRAM, CRAM & VSRAM is limited during active display: */2196/* H32 mode -> 16 access per line */2197/* H40 mode -> 18 access per line */2198/* */2199/* with fixed access slots timings detailled below. */2200/* */2201/* Each VRAM access is byte wide, so one VRAM write (word) need two slots. */2202/* */2203/*--------------------------------------------------------------------------*/22042205static void vdp_fifo_update(unsigned int cycles)2206{2207int slots, count = 0;22082209const int *fifo_timing;22102211const int fifo_cycles_h32[16+2] =2212{2213230, 510, 810, 970, 1130, 1450, 1610, 1770, 2090, 2250, 2410, 2730, 2890, 3050, 3350, 3370,2214MCYCLES_PER_LINE + 230, MCYCLES_PER_LINE + 5102215};22162217const int fifo_cycles_h40[18+2] =2218{2219352, 820, 948, 1076, 1332, 1460, 1588, 1844, 1972, 2100, 2356, 2484, 2612, 2868, 2996, 3124, 3364, 3380,2220MCYCLES_PER_LINE + 352, MCYCLES_PER_LINE + 8202221};222222232224/* number of access slots up to current line */2225if (reg[12] & 0x01)2226{2227fifo_timing = fifo_cycles_h40;2228slots = 18 * (cycles / MCYCLES_PER_LINE);2229}2230else2231{2232fifo_timing = fifo_cycles_h32;2233slots = 16 * (cycles / MCYCLES_PER_LINE);2234}22352236/* number of access slots within current line */2237cycles = cycles % MCYCLES_PER_LINE;2238while (fifo_timing[count] <= cycles)2239{2240count++;2241}22422243/* number of processed FIFO entries since last access */2244slots = (slots + count - fifo_slots) >> fifo_byte_access;22452246if (slots > 0)2247{2248/* process FIFO entries */2249fifo_write_cnt -= slots;22502251/* Clear FIFO full flag */2252status &= 0xFEFF;22532254if (fifo_write_cnt <= 0)2255{2256/* No more FIFO entries */2257fifo_write_cnt = 0;22582259/* Set FIFO empty flag */2260status |= 0x200;2261}22622263/* Update FIFO access slot counter */2264fifo_slots += (slots << fifo_byte_access);2265}22662267/* next FIFO update cycle */2268fifo_cycles = mcycles_vdp + fifo_timing[count | fifo_byte_access];2269}227022712272/*--------------------------------------------------------------------------*/2273/* Internal 16-bit data bus access function (Mode 5 only) */2274/*--------------------------------------------------------------------------*/2275static void vdp_bus_w(unsigned int data)2276{2277/* write data to next FIFO entry */2278fifo[fifo_idx] = data;22792280/* increment FIFO write pointer */2281fifo_idx = (fifo_idx + 1) & 3;22822283/* Check destination code (CD0-CD3) */2284switch (code & 0x0F)2285{2286case 0x01: /* VRAM */2287{2288/* VRAM address */2289int index = addr & 0xFFFE;22902291/* Pointer to VRAM */2292uint16 *p = (uint16 *)&vram[index];22932294/* Byte-swap data if A0 is set */2295if (addr & 1)2296{2297data = ((data >> 8) | (data << 8)) & 0xFFFF;2298}22992300/* Intercept writes to Sprite Attribute Table */2301if ((index & sat_base_mask) == satb)2302{2303/* Update internal SAT */2304*(uint16 *) &sat[index & sat_addr_mask] = data;2305}23062307/* Only write unique data to VRAM */2308if (data != *p)2309{2310int name;23112312/* Write data to VRAM */2313*p = data;23142315/* Update pattern cache */2316MARK_BG_DIRTY (index);2317}23182319#ifdef LOGVDP2320error("[%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));2321#endif2322break;2323}23242325case 0x03: /* CRAM */2326{2327/* Pointer to CRAM 9-bit word */2328uint16 *p = (uint16 *)&cram[addr & 0x7E];23292330/* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */2331data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1);23322333/* Check if CRAM data is being modified */2334if (data != *p)2335{2336/* CRAM index (64 words) */2337int index = (addr >> 1) & 0x3F;23382339/* Write CRAM data */2340*p = data;23412342/* Color entry 0 of each palette is never displayed (transparent pixel) */2343if (index & 0x0F)2344{2345/* Update color palette */2346color_update_m5(index, data);2347}23482349/* Update backdrop color */2350if (index == border)2351{2352color_update_m5(0x00, data);2353}23542355/* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */2356if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))2357{2358/* Remap current line */2359remap_line(v_counter);2360}2361}2362#ifdef LOGVDP2363error("[%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));2364#endif2365break;2366}23672368case 0x05: /* VSRAM */2369{2370*(uint16 *)&vsram[addr & 0x7E] = data;23712372/* 2-cell Vscroll mode */2373if (reg[11] & 0x04)2374{2375/* VSRAM writes during HBLANK (Adventures of Batman & Robin) */2376if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))2377{2378/* Remap current line */2379render_line(v_counter);2380}2381}2382#ifdef LOGVDP2383error("[%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));2384#endif2385break;2386}23872388default:2389{2390/* add some delay until 68k periodical wait-states are accurately emulated ("Clue", "Microcosm") */2391m68k.cycles += 2;2392#ifdef LOGERROR2393error("[%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));2394#endif2395break;2396}2397}23982399/* Increment address register */2400addr += reg[15];2401}240224032404/*--------------------------------------------------------------------------*/2405/* 68k bus interface (Mega Drive VDP only) */2406/*--------------------------------------------------------------------------*/24072408static void vdp_68k_data_w_m4(unsigned int data)2409{2410/* Clear pending flag */2411pending = 0;24122413/* Restricted VDP writes during active display */2414if (!(status & 8) && (reg[1] & 0x40))2415{2416/* Update VDP FIFO */2417vdp_fifo_update(m68k.cycles);24182419/* Clear FIFO empty flag */2420status &= 0xFDFF;24212422/* up to 4 words can be stored */2423if (fifo_write_cnt < 4)2424{2425/* Increment FIFO counter */2426fifo_write_cnt++;24272428/* Set FIFO full flag if 4 words are stored */2429status |= ((fifo_write_cnt & 4) << 6);2430}2431else2432{2433/* CPU is halted until next FIFO entry processing */2434m68k.cycles = fifo_cycles;24352436/* Update FIFO access slot counter */2437fifo_slots = fifo_slots + 1 + fifo_byte_access;2438}2439}24402441/* Check destination code */2442if (code & 0x02)2443{2444/* CRAM index (32 words) */2445int index = addr & 0x1F;24462447/* Pointer to CRAM 9-bit word */2448uint16 *p = (uint16 *)&cram[index << 1];24492450/* Pack 16-bit data (xxx000BBGGRR) to 9-bit CRAM data (xxxBBGGRR) */2451data = ((data & 0xE00) >> 3) | (data & 0x3F);24522453/* Check if CRAM data is being modified */2454if (data != *p)2455{2456/* Write CRAM data */2457*p = data;24582459/* Update color palette */2460color_update_m4(index, data);24612462/* Update backdrop color */2463if (index == (0x10 | (border & 0x0F)))2464{2465color_update_m4(0x40, data);2466}2467}2468}2469else2470{2471/* VRAM address (interleaved format) */2472int index = ((addr << 1) & 0x3FC) | ((addr & 0x200) >> 8) | (addr & 0x3C00);24732474/* Pointer to VRAM */2475uint16 *p = (uint16 *)&vram[index];24762477/* Byte-swap data if A0 is set */2478if (addr & 1)2479{2480data = ((data >> 8) | (data << 8)) & 0xFFFF;2481}24822483/* Only write unique data to VRAM */2484if (data != *p)2485{2486int name;24872488/* Write data to VRAM */2489*p = data;24902491/* Update the pattern cache */2492MARK_BG_DIRTY (index);2493}2494}24952496/* Increment address register (TODO: check how address is incremented in Mode 4) */2497addr += (reg[15] + 1);2498}24992500static void vdp_68k_data_w_m5(unsigned int data)2501{2502/* Clear pending flag */2503pending = 0;25042505/* Restricted VDP writes during active display */2506if (!(status & 8) && (reg[1] & 0x40))2507{2508/* Update VDP FIFO */2509vdp_fifo_update(m68k.cycles);25102511/* Clear FIFO empty flag */2512status &= 0xFDFF;25132514/* up to 4 words can be stored */2515if (fifo_write_cnt < 4)2516{2517/* Increment FIFO counter */2518fifo_write_cnt++;25192520/* Set FIFO full flag if 4 words are stored */2521status |= ((fifo_write_cnt & 4) << 6);2522}2523else2524{2525/* CPU is halted until next FIFO entry processing (Chaos Engine / Soldiers of Fortune, Double Clutch, Titan Overdrive Demo) */2526m68k.cycles = fifo_cycles;25272528/* Update FIFO access slot counter */2529fifo_slots += (1 + fifo_byte_access);2530}2531}25322533/* Write data */2534vdp_bus_w(data);25352536/* Check if DMA Fill is pending */2537if (dmafill)2538{2539/* Clear DMA Fill pending flag */2540dmafill = 0;25412542/* DMA length */2543dma_length = (reg[20] << 8) | reg[19];25442545/* Zero DMA length (pre-decrementing counter) */2546if (!dma_length)2547{2548dma_length = 0x10000;2549}25502551/* Trigger DMA */2552vdp_dma_update(m68k.cycles);2553}2554}25552556static unsigned int vdp_68k_data_r_m4(void)2557{2558/* VRAM address (interleaved format) */2559int index = ((addr << 1) & 0x3FC) | ((addr & 0x200) >> 8) | (addr & 0x3C00);25602561/* Clear pending flag */2562pending = 0;25632564/* Increment address register (TODO: check how address is incremented in Mode 4) */2565addr += (reg[15] + 1);25662567/* Read VRAM data */2568return *(uint16 *) &vram[index];2569}25702571static unsigned int vdp_68k_data_r_m5(void)2572{2573uint16 data = 0;25742575/* Clear pending flag */2576pending = 0;25772578/* Check destination code (CD0-CD3) & CD4 */2579switch (code & 0x1F)2580{2581case 0x00:2582{2583/* read two bytes from VRAM */2584data = *(uint16 *)&vram[addr & 0xFFFE];25852586#ifdef LOGVDP2587error("[%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));2588#endif2589break;2590}25912592case 0x04:2593{2594/* VSRAM index */2595int index = addr & 0x7E;25962597/* Check against VSRAM max size (80 x 11-bits) */2598if (index >= 0x50)2599{2600/* Wrap to address 0 (TODO: check if still true with Genesis 3 model) */2601index = 0;2602}26032604/* Read 11-bit word from VSRAM */2605data = *(uint16 *)&vsram[index] & 0x7FF;26062607/* Unused bits are set using data from next available FIFO entry */2608data |= (fifo[fifo_idx] & ~0x7FF);26092610#ifdef LOGVDP2611error("[%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));2612#endif2613break;2614}26152616case 0x08:2617{2618/* Read 9-bit word from CRAM */2619data = *(uint16 *)&cram[addr & 0x7E];26202621/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit bus data (BBB0GGG0RRR0) */2622data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);26232624/* Unused bits are set using data from next available FIFO entry */2625data |= (fifo[fifo_idx] & ~0xEEE);26262627#ifdef LOGVDP2628error("[%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));2629#endif2630break;2631}26322633case 0x0c: /* undocumented 8-bit VRAM read */2634{2635/* Read one byte from VRAM adjacent address */2636data = READ_BYTE(vram, addr ^ 1);26372638/* Unused bits are set using data from next available FIFO entry */2639data |= (fifo[fifo_idx] & ~0xFF);26402641#ifdef LOGVDP2642error("[%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));2643#endif2644break;2645}26462647default:2648{2649/* Invalid code value (normally locks VDP, hard reset required) */2650#ifdef LOGERROR2651error("[%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));2652#endif2653break;2654}2655}26562657/* Increment address register */2658addr += reg[15];26592660/* Return data */2661return data;2662}266326642665/*--------------------------------------------------------------------------*/2666/* Z80 bus interface (Mega Drive VDP in Master System compatibility mode) */2667/*--------------------------------------------------------------------------*/26682669static void vdp_z80_data_w_m4(unsigned int data)2670{2671/* Clear pending flag */2672pending = 0;26732674/* Check destination code */2675if (code & 0x02)2676{2677/* CRAM index (32 words) */2678int index = addr & 0x1F;26792680/* Pointer to CRAM word */2681uint16 *p = (uint16 *)&cram[index << 1];26822683/* Check if CRAM data is being modified */2684if (data != *p)2685{2686/* Write CRAM data */2687*p = data;26882689/* Update color palette */2690color_update_m4(index, data);26912692/* Update backdrop color */2693if (index == (0x10 | (border & 0x0F)))2694{2695color_update_m4(0x40, data);2696}2697}2698}2699else2700{2701/* VRAM address */2702int index = addr & 0x3FFF;27032704/* Only write unique data to VRAM */2705if (data != vram[index])2706{2707int name;27082709/* Write data */2710vram[index] = data;27112712/* Update pattern cache */2713MARK_BG_DIRTY(index);2714}2715}27162717/* Increment address register (TODO: check how address is incremented in Mode 4) */2718addr += (reg[15] + 1);2719}27202721static void vdp_z80_data_w_m5(unsigned int data)2722{2723/* Clear pending flag */2724pending = 0;27252726/* Push byte into FIFO */2727fifo[fifo_idx] = data << 8;2728fifo_idx = (fifo_idx + 1) & 3;27292730/* Check destination code (CD0-CD3) */2731switch (code & 0x0F)2732{2733case 0x01: /* VRAM */2734{2735/* VRAM address (write low byte to even address & high byte to odd address) */2736int index = addr ^ 1;27372738/* Intercept writes to Sprite Attribute Table */2739if ((index & sat_base_mask) == satb)2740{2741/* Update internal SAT */2742WRITE_BYTE(sat, index & sat_addr_mask, data);2743}27442745/* Only write unique data to VRAM */2746if (data != READ_BYTE(vram, index))2747{2748int name;27492750/* Write data */2751WRITE_BYTE(vram, index, data);27522753/* Update pattern cache */2754MARK_BG_DIRTY (index);2755}2756break;2757}27582759case 0x03: /* CRAM */2760{2761/* Pointer to CRAM word */2762uint16 *p = (uint16 *)&cram[addr & 0x7E];27632764/* Pack 8-bit value into 9-bit CRAM data */2765if (addr & 1)2766{2767/* Write high byte (0000BBB0 -> BBBxxxxxx) */2768data = (*p & 0x3F) | ((data & 0x0E) << 5);2769}2770else2771{2772/* Write low byte (GGG0RRR0 -> xxxGGGRRR) */2773data = (*p & 0x1C0) | ((data & 0x0E) >> 1)| ((data & 0xE0) >> 2);2774}27752776/* Check if CRAM data is being modified */2777if (data != *p)2778{2779/* CRAM index (64 words) */2780int index = (addr >> 1) & 0x3F;27812782/* Write CRAM data */2783*p = data;27842785/* Color entry 0 of each palette is never displayed (transparent pixel) */2786if (index & 0x0F)2787{2788/* Update color palette */2789color_update_m5(index, data);2790}27912792/* Update backdrop color */2793if (index == border)2794{2795color_update_m5(0x00, data);2796}2797}2798break;2799}28002801case 0x05: /* VSRAM */2802{2803/* Write low byte to even address & high byte to odd address */2804WRITE_BYTE(vsram, (addr & 0x7F) ^ 1, data);2805break;2806}2807}28082809/* Increment address register */2810addr += reg[15];28112812/* Check if DMA Fill is pending */2813if (dmafill)2814{2815/* Clear DMA Fill pending flag */2816dmafill = 0;28172818/* DMA length */2819dma_length = (reg[20] << 8) | reg[19];28202821/* Zero DMA length (pre-decrementing counter) */2822if (!dma_length)2823{2824dma_length = 0x10000;2825}28262827/* Trigger DMA */2828vdp_dma_update(Z80.cycles);2829}2830}28312832static unsigned int vdp_z80_data_r_m4(void)2833{2834/* Read buffer */2835unsigned int data = fifo[0];28362837/* Clear pending flag */2838pending = 0;28392840/* Process next read */2841fifo[0] = vram[addr & 0x3FFF];28422843/* Increment address register (TODO: check how address is incremented in Mode 4) */2844addr += (reg[15] + 1);28452846/* Return data */2847return data;2848}28492850static unsigned int vdp_z80_data_r_m5(void)2851{2852unsigned int data = 0;28532854/* Clear pending flag */2855pending = 0;28562857/* Check destination code (CD0-CD3) & CD4 */2858switch (code & 0x1F)2859{2860case 0x00: /* VRAM */2861{2862/* Return low byte from even address & high byte from odd address */2863data = READ_BYTE(vram, addr ^ 1);2864break;2865}28662867case 0x04: /* VSRAM */2868{2869/* Return low byte from even address & high byte from odd address */2870data = READ_BYTE(vsram, (addr & 0x7F) ^ 1);2871break;2872}28732874case 0x08: /* CRAM */2875{2876/* Read CRAM data */2877data = *(uint16 *)&cram[addr & 0x7E];28782879/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit data (BBB0GGG0RRR0) */2880data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);28812882/* Return low byte from even address & high byte from odd address */2883if (addr & 1)2884{2885data = data >> 8;2886}28872888data &= 0xFF;2889break;2890}2891}28922893/* Increment address register */2894addr += reg[15];28952896/* Return data */2897return data;2898}289929002901/*-----------------------------------------------------------------------------*/2902/* Z80 bus interface (Master System, Game Gear & SG-1000 VDP) */2903/*-----------------------------------------------------------------------------*/29042905static void vdp_z80_data_w_ms(unsigned int data)2906{2907/* Clear pending flag */2908pending = 0;29092910if (code < 3)2911{2912int index;29132914/* Check if we are already on next line */2915int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2916if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2917{2918/* Render next line */2919v_counter = line;2920render_line(line);2921}29222923/* VRAM address */2924index = addr & 0x3FFF;29252926/* VRAM write */2927if (data != vram[index])2928{2929int name;2930vram[index] = data;2931MARK_BG_DIRTY(index);2932}29332934#ifdef LOGVDP2935error("[%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);2936#endif2937}2938else2939{2940/* CRAM address */2941int index = addr & 0x1F;29422943/* Pointer to CRAM word */2944uint16 *p = (uint16 *)&cram[index << 1];29452946/* Check if CRAM data is being modified */2947if (data != *p)2948{2949/* Write CRAM data */2950*p = data;29512952/* Update color palette */2953color_update_m4(index, data);29542955/* Update backdrop color */2956if (index == (0x10 | (border & 0x0F)))2957{2958color_update_m4(0x40, data);2959}2960}2961#ifdef LOGVDP2962error("[%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);2963#endif2964}29652966/* Update read buffer */2967fifo[0] = data;29682969/* Update address register */2970addr++;2971}29722973static void vdp_z80_data_w_gg(unsigned int data)2974{2975/* Clear pending flag */2976pending = 0;29772978if (code < 3)2979{2980int index;29812982/* Check if we are already on next line*/2983int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;2984if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))2985{2986/* Render next line */2987v_counter = line;2988render_line(line);2989}29902991/* VRAM address */2992index = addr & 0x3FFF;29932994/* VRAM write */2995if (data != vram[index])2996{2997int name;2998vram[index] = data;2999MARK_BG_DIRTY(index);3000}3001#ifdef LOGVDP3002error("[%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);3003#endif3004}3005else3006{3007if (addr & 1)3008{3009/* Pointer to CRAM word */3010uint16 *p = (uint16 *)&cram[addr & 0x3E];30113012/* 12-bit data word */3013data = (data << 8) | cached_write;30143015/* Check if CRAM data is being modified */3016if (data != *p)3017{3018/* Color index (0-31) */3019int index = (addr >> 1) & 0x1F;30203021/* Write CRAM data */3022*p = data;30233024/* Update color palette */3025color_update_m4(index, data);30263027/* Update backdrop color */3028if (index == (0x10 | (border & 0x0F)))3029{3030color_update_m4(0x40, data);3031}3032}3033}3034else3035{3036/* Latch LSB */3037cached_write = data;3038}3039#ifdef LOGVDP3040error("[%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);3041#endif3042}30433044/* Update read buffer */3045fifo[0] = data;30463047/* Update address register */3048addr++;3049}30503051static void vdp_z80_data_w_sg(unsigned int data)3052{3053/* VRAM address */3054int index = addr & 0x3FFF;30553056/* Clear pending flag */3057pending = 0;30583059/* 4K address decoding (cf. tms9918a.txt) */3060if (!(reg[1] & 0x80))3061{3062index = (index & 0x203F) | ((index >> 6) & 0x40) | ((index << 1) & 0x1F80);3063}30643065/* VRAM write */3066vram[index] = data;30673068/* Update address register */3069addr++;30703071#ifdef LOGVDP3072error("[%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);3073#endif3074}30753076/*--------------------------------------------------------------------------*/3077/* DMA operations (Mega Drive VDP only) */3078/*--------------------------------------------------------------------------*/30793080void CDLog68k(uint addr, uint flags);30813082/* DMA from 68K bus: $000000-$7FFFFF (external area) */3083static void vdp_dma_68k_ext(unsigned int length)3084{3085uint16 data;30863087/* 68k bus source address */3088uint32 source = (reg[23] << 17) | (dma_src << 1);30893090do3091{3092/* Read data word from 68k bus */3093if (m68k.memory_map[source>>16].read16)3094{3095data = m68k.memory_map[source>>16].read16(source);3096}3097else3098{3099data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF));3100}31013102if(biz_cdcallback)3103{3104//if((code & 0x0F) == 0x01) //VRAM target //lets handle everything here3105{3106CDLog68k(source,eCDLog_Flags_DMASource);3107CDLog68k(source+1,eCDLog_Flags_DMASource);3108}3109}311031113112/* Increment source address */3113source += 2;31143115/* 128k DMA window */3116source = (reg[23] << 17) | (source & 0x1FFFF);31173118/* Write data word to VRAM, CRAM or VSRAM */3119vdp_bus_w(data);3120}3121while (--length);31223123/* Update DMA source address */3124dma_src = (source >> 1) & 0xffff;3125}31263127/* DMA from 68K bus: $800000-$FFFFFF (internal area) except I/O area */3128static void vdp_dma_68k_ram(unsigned int length)3129{3130uint16 data;31313132/* 68k bus source address */3133uint32 source = (reg[23] << 17) | (dma_src << 1);31343135do3136{3137/* access Work-RAM by default */3138data = *(uint16 *)(work_ram + (source & 0xFFFF));31393140/* Increment source address */3141source += 2;31423143/* 128k DMA window */3144source = (reg[23] << 17) | (source & 0x1FFFF);31453146/* Write data word to VRAM, CRAM or VSRAM */3147vdp_bus_w(data);3148}3149while (--length);31503151/* Update DMA source address */3152dma_src = (source >> 1) & 0xffff;3153}31543155/* DMA from 68K bus: $A00000-$A1FFFF (I/O area) specific */3156static void vdp_dma_68k_io(unsigned int length)3157{3158uint16 data;31593160/* 68k bus source address */3161uint32 source = (reg[23] << 17) | (dma_src << 1);31623163do3164{3165/* Z80 area */3166if (source <= 0xA0FFFF)3167{3168/* Return $FFFF only when the Z80 isn't hogging the Z-bus.3169(e.g. Z80 isn't reset and 68000 has the bus) */3170data = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xFFFF)) : 0xFFFF);3171}31723173/* The I/O chip and work RAM try to drive the data bus which results3174in both values being combined in random ways when read.3175We return the I/O chip values which seem to have precedence, */3176else if (source <= 0xA1001F)3177{3178data = io_68k_read((source >> 1) & 0x0F);3179data = (data << 8 | data);3180}31813182/* All remaining locations access work RAM */3183else3184{3185data = *(uint16 *)(work_ram + (source & 0xFFFF));3186}31873188/* Increment source address */3189source += 2;31903191/* 128k DMA window */3192source = (reg[23] << 17) | (source & 0x1FFFF);31933194/* Write data to VRAM, CRAM or VSRAM */3195vdp_bus_w(data);3196}3197while (--length);31983199/* Update DMA source address */3200dma_src = (source >> 1) & 0xffff;3201}32023203/* VRAM Copy */3204static void vdp_dma_copy(unsigned int length)3205{3206/* CD4 should be set (CD0-CD3 ignored) otherwise VDP locks (hard reset needed) */3207if (code & 0x10)3208{3209int name;3210uint8 data;32113212/* VRAM source address */3213uint16 source = dma_src;32143215do3216{3217/* Read byte from adjacent VRAM source address */3218data = READ_BYTE(vram, source ^ 1);32193220/* Intercept writes to Sprite Attribute Table */3221if ((addr & sat_base_mask) == satb)3222{3223/* Update internal SAT */3224WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data);3225}32263227/* Write byte to adjacent VRAM destination address */3228WRITE_BYTE(vram, addr ^ 1, data);32293230/* Update pattern cache */3231MARK_BG_DIRTY(addr);32323233/* Increment VRAM source address */3234source++;32353236/* Increment VRAM destination address */3237addr += reg[15];3238}3239while (--length);32403241/* Update DMA source address */3242dma_src = source;3243}3244}32453246/* DMA Fill */3247static void vdp_dma_fill(unsigned int length)3248{3249/* Check destination code (CD0-CD3) */3250switch (code & 0x0F)3251{3252case 0x01: /* VRAM */3253{3254int name;32553256/* Get source data from last written FIFO entry */3257uint8 data = fifo[(fifo_idx+3)&3] >> 8;32583259do3260{3261/* Intercept writes to Sprite Attribute Table */3262if ((addr & sat_base_mask) == satb)3263{3264/* Update internal SAT */3265WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data);3266}32673268/* Write byte to adjacent VRAM address */3269WRITE_BYTE(vram, addr ^ 1, data);32703271/* Update pattern cache */3272MARK_BG_DIRTY (addr);32733274/* Increment VRAM address */3275addr += reg[15];3276}3277while (--length);3278break;3279}32803281case 0x03: /* CRAM */3282{3283/* Get source data from next available FIFO entry */3284uint16 data = fifo[fifo_idx];32853286/* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */3287data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1);32883289do3290{3291/* Pointer to CRAM 9-bit word */3292uint16 *p = (uint16 *)&cram[addr & 0x7E];32933294/* Check if CRAM data is being modified */3295if (data != *p)3296{3297/* CRAM index (64 words) */3298int index = (addr >> 1) & 0x3F;32993300/* Write CRAM data */3301*p = data;33023303/* Color entry 0 of each palette is never displayed (transparent pixel) */3304if (index & 0x0F)3305{3306/* Update color palette */3307color_update_m5(index, data);3308}33093310/* Update backdrop color */3311if (index == border)3312{3313color_update_m5(0x00, data);3314}3315}33163317/* Increment CRAM address */3318addr += reg[15];3319}3320while (--length);3321break;3322}33233324case 0x05: /* VSRAM */3325{3326/* Get source data from next available FIFO entry */3327uint16 data = fifo[fifo_idx];33283329do3330{3331/* Write VSRAM data */3332*(uint16 *)&vsram[addr & 0x7E] = data;33333334/* Increment VSRAM address */3335addr += reg[15];3336}3337while (--length);3338break;3339}33403341default:3342{3343/* invalid destination does nothing (Williams Greatest Hits after soft reset) */33443345/* address is still incremented */3346addr += reg[15] * length;3347}3348}3349}335033513352