A7800DS/arm9/source/emu/Maria.c

1062 lines
42 KiB
C

// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// Copyright 2005 Greg Stanton
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Maria.c
// ----------------------------------------------------------------------------
#include "Maria.h"
#include "ProSystem.h"
#include "Database.h"
extern uint bRenderFrame;
union ColorUnion
{
int32 color32;
struct {
byte color0;
byte color1;
byte color2;
byte color3;
} by;
struct {
word color0;
word color1;
} wo;
};
static byte maria_lineRAM[256] __attribute__((section(".dtcm")));
word* maria_surface __attribute__((section(".dtcm"))) = 0;
uint maria_scanline __attribute__((section(".dtcm"))) = 1;
u8 write_mask_low __attribute__((section(".dtcm")));
u8 write_mask_high __attribute__((section(".dtcm")));
u8 bg8 __attribute__((section(".dtcm")));
uint maria_cycles __attribute__((section(".dtcm")));
static lpair maria_dpp __attribute__((section(".dtcm")));
static lpair maria_dp __attribute__((section(".dtcm")));
static lpair maria_pp __attribute__((section(".dtcm")));
static byte maria_horizontal __attribute__((section(".dtcm")));
static byte maria_palette __attribute__((section(".dtcm")));
static int maria_offset __attribute__((section(".dtcm")));
static uint maria_h8_h16 __attribute__((section(".dtcm")));
static u32 maria_wmode __attribute__((section(".dtcm")));
word *framePtr __attribute__((section(".dtcm"))) = (word *)0;
u32 color_lookup_160AB[256][256];
byte color_lookup_320AC[256] __attribute__((section(".dtcm")));
u32 maria_charbase __attribute__((section(".dtcm")));
u16 banksets_mask __attribute__((section(".dtcm"))) = 0x0000;
void mariaBANK_RenderScanlineTOP(void);
void mariaBANK_RenderScanline(void);
extern u32 bg32;
#define MARIA_CYCLE_LIMIT 426
#define MARIA_LINERAM_SIZE 160
#define MARIA_CYCLES_DMA_INITIAL_COST 0
#define MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE 24
#define MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE 16
#define MARIA_CYCLES_4_BYTE_HEADER 8
#define MARIA_CYCLES_5_BYTE_HEADER 10
#define MARIA_CYCLES_NMI_COST 17
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void maria_Reset( )
{
maria_Clear();
maria_scanline = 1;
// These values need to be reset to allow switching between carts.
maria_cycles = 0;
maria_dpp.w = 0;
maria_dp.w = 0;
maria_pp.w = 0;
maria_horizontal = 0;
maria_palette = 0;
maria_offset = 0;
maria_h8_h16 = 0x0000;
maria_wmode = 0;
bg32 = 0x00000000;
bg8=0x00;
maria_charbase = 0;
banksets_mask = 0x0000;
if ((myCartInfo.cardtype == CARTRIDGE_TYPE_BANKSETS) || (myCartInfo.cardtype == CARTRIDGE_TYPE_BANKSETS_RAM)) banksets_mask = 0x8000;
if ((myCartInfo.cardtype == CARTRIDGE_TYPE_BANKSETS_HALTRAM)) banksets_mask = 0xC000;
// ----------------------------------------------------------------------------------
// Build the 160 A/B color lookup table for a few frames of increased performance
// ----------------------------------------------------------------------------------
for (uint color=0; color<256; color++)
{
for (uint color1=0; color1<256; color1++)
{
color_lookup_160AB[color][color1] = color | (color<<8) | (color1<<16) | (color1<<24);
}
color_lookup_320AC[color] = (color & 28) | ((color & 1) << 1);
}
}
// ----------------------------------------------------------------------------
// Clear
// ----------------------------------------------------------------------------
void maria_Clear( )
{
maria_surface = bufVideo;
memset(maria_surface, 0x00, MARIA_SURFACE_SIZE);
}
// ----------------------------------------------------------------------------
// StoreCells - 4 bytes at a time
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void maria_StoreCells4(byte data)
{
if((maria_horizontal) < MARIA_LINERAM_SIZE)
{
byte *ptr = &(maria_lineRAM[maria_horizontal]);
if (data & 0xC0) *ptr++ = maria_palette | ((data ) >> 6); else ptr++;
if (data & 0x30) *ptr++ = maria_palette | ((data & 0x30) >> 4); else ptr++;
if (data & 0x0C) *ptr++ = maria_palette | ((data & 0x0C) >> 2); else ptr++;
if (data & 0x03) *ptr = maria_palette | (data & 0x03);
}
}
static inline __attribute__((always_inline)) void mariaROO_StoreCells4(byte data)
{
if((maria_horizontal) < MARIA_LINERAM_SIZE)
{
byte *ptr = &(maria_lineRAM[maria_horizontal]);
if (memory_ram[CTRL] & 4)
{
*ptr++ = maria_palette | ((data ) >> 6);
*ptr++ = maria_palette | ((data & 0x30) >> 4);
*ptr++ = maria_palette | ((data & 0x0C) >> 2);
*ptr = maria_palette | (data & 0x03);
}
else
{
if (data & 0xC0) *ptr++ = maria_palette | ((data ) >> 6); else ptr++;
if (data & 0x30) *ptr++ = maria_palette | ((data & 0x30) >> 4); else ptr++;
if (data & 0x0C) *ptr++ = maria_palette | ((data & 0x0C) >> 2); else ptr++;
if (data & 0x03) *ptr = maria_palette | (data & 0x03);
}
}
}
// ----------------------------------------------------------------------------
// StoreCell - WriteMode
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void maria_StoreCellWriteMode(byte data)
{
if (maria_horizontal < MARIA_LINERAM_SIZE)
{
byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
if (data & write_mask_high) // high
{
*ptr = (maria_palette & 0x10) | (data >> 4);
}
if (data & write_mask_low) // low
{
ptr++;
*ptr = (maria_palette & 0x10) | (data & 0x0F);
}
}
}
static inline __attribute__((always_inline)) void mariaROO_StoreCellWriteMode(byte data)
{
if (maria_horizontal < MARIA_LINERAM_SIZE)
{
byte *ptr = (byte *)&maria_lineRAM[maria_horizontal];
if (data & write_mask_high) // high
{
*ptr = (maria_palette & 0x10) | (data >> 4);
}
else
{
if ((memory_ram[CTRL] & 4))
{
*ptr = maria_palette;
}
}
if (data & write_mask_low) // low
{
ptr++;
*ptr = (maria_palette & 0x10) | (data & 0x0F);
}
else
{
if ((memory_ram[CTRL] & 4))
{
ptr++;
*ptr = maria_palette;
}
}
}
}
// ----------------------------------------------------------------------------
// IsHoleyDMA
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) bool maria_IsHoleyDMA()
{
if (maria_pp.w & 0x8000) // Holey DMA is only possible in the upper half of the CART space
{
if (maria_pp.w & maria_h8_h16) return true;
}
return false;
}
// ----------------------------------------------------------------------------
// GetColor
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) byte maria_GetColor(byte data)
{
return (data & 3) ? memory_ram[BACKGRND | data] : bg8;
}
static u8 write_mode_lookup[256] __attribute__((section(".dtcm"))) =
{
0x00, 0x04, 0x08, 0x0C, 0x40, 0x44, 0x48, 0x4C, 0x80, 0x84, 0x88, 0x8C, 0xC0, 0xC4, 0xC8, 0xCC,
0x01, 0x05, 0x09, 0x0D, 0x41, 0x45, 0x49, 0x4D, 0x81, 0x85, 0x89, 0x8D, 0xC1, 0xC5, 0xC9, 0xCD,
0x02, 0x06, 0x0A, 0x0E, 0x42, 0x46, 0x4A, 0x4E, 0x82, 0x86, 0x8A, 0x8E, 0xC2, 0xC6, 0xCA, 0xCE,
0x03, 0x07, 0x0B, 0x0F, 0x43, 0x47, 0x4B, 0x4F, 0x83, 0x87, 0x8B, 0x8F, 0xC3, 0xC7, 0xCB, 0xCF,
0x10, 0x14, 0x18, 0x1C, 0x50, 0x54, 0x58, 0x5C, 0x90, 0x94, 0x98, 0x9C, 0xD0, 0xD4, 0xD8, 0xDC,
0x11, 0x15, 0x19, 0x1D, 0x51, 0x55, 0x59, 0x5D, 0x91, 0x95, 0x99, 0x9D, 0xD1, 0xD5, 0xD9, 0xDD,
0x12, 0x16, 0x1A, 0x1E, 0x52, 0x56, 0x5A, 0x5E, 0x92, 0x96, 0x9A, 0x9E, 0xD2, 0xD6, 0xDA, 0xDE,
0x13, 0x17, 0x1B, 0x1F, 0x53, 0x57, 0x5B, 0x5F, 0x93, 0x97, 0x9B, 0x9F, 0xD3, 0xD7, 0xDB, 0xDF,
0x20, 0x24, 0x28, 0x2C, 0x60, 0x64, 0x68, 0x6C, 0xA0, 0xA4, 0xA8, 0xAC, 0xE0, 0xE4, 0xE8, 0xEC,
0x21, 0x25, 0x29, 0x2D, 0x61, 0x65, 0x69, 0x6D, 0xA1, 0xA5, 0xA9, 0xAD, 0xE1, 0xE5, 0xE9, 0xED,
0x22, 0x26, 0x2A, 0x2E, 0x62, 0x66, 0x6A, 0x6E, 0xA2, 0xA6, 0xAA, 0xAE, 0xE2, 0xE6, 0xEA, 0xEE,
0x23, 0x27, 0x2B, 0x2F, 0x63, 0x67, 0x6B, 0x6F, 0xA3, 0xA7, 0xAB, 0xAF, 0xE3, 0xE7, 0xEB, 0xEF,
0x30, 0x34, 0x38, 0x3C, 0x70, 0x74, 0x78, 0x7C, 0xB0, 0xB4, 0xB8, 0xBC, 0xF0, 0xF4, 0xF8, 0xFC,
0x31, 0x35, 0x39, 0x3D, 0x71, 0x75, 0x79, 0x7D, 0xB1, 0xB5, 0xB9, 0xBD, 0xF1, 0xF5, 0xF9, 0xFD,
0x32, 0x36, 0x3A, 0x3E, 0x72, 0x76, 0x7A, 0x7E, 0xB2, 0xB6, 0xBA, 0xBE, 0xF2, 0xF6, 0xFA, 0xFE,
0x33, 0x37, 0x3B, 0x3F, 0x73, 0x77, 0x7B, 0x7F, 0xB3, 0xB7, 0xBB, 0xBF, 0xF3, 0xF7, 0xFB, 0xFF
};
static u8 write_mode_lookup_mode2A[] __attribute__((section(".dtcm"))) =
{
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03,
0x10, 0x10, 0x12, 0x12, 0x10, 0x10, 0x12, 0x12, 0x11, 0x11, 0x13, 0x13, 0x11, 0x11, 0x13, 0x13
};
static u8 write_mode_lookup_mode2B[] __attribute__((section(".dtcm"))) =
{
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13,
0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x01, 0x03, 0x01, 0x03,
0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0x11, 0x13
};
static u8 artifacting_lookup_bright[] __attribute__((section(".dtcm"))) = { 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0A };
static u8 artifacting_lookup_dull[] __attribute__((section(".dtcm"))) = { 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04 };
// ----------------------------------------------------------------------------
// WriteLineRAM
// ----------------------------------------------------------------------------
static ITCM_CODE void maria_WriteLineRAM(word * buffer)
{
u8 buffer_local[MARIA_LINERAM_SIZE * 2];
union ColorUnion colors;
uint32 * pix = (uint32 * ) buffer;
uint32 * ptr = (uint32 * ) & maria_lineRAM[0];
byte rmode = memory_ram[CTRL] & 3;
if(use_composite_filtering)
{
pix = (uint32 * ) buffer_local;
}
if(rmode == 0) // 160A/B
{
for(uint index = 0; index < MARIA_LINERAM_SIZE / 4; index++)
{
colors.color32 = * ptr++;
if(colors.color32 == 0)
{
* pix++ = bg32;
* pix++ = bg32;
}
else
{
if((colors.wo.color0 == 0))
{
* pix++ = bg32;
}
else
{
* pix++ = color_lookup_160AB[maria_GetColor(colors.by.color0)][maria_GetColor(colors.by.color1)];
}
if((colors.wo.color1 == 0))
{
* pix++ = bg32;
}
else
{
* pix++ = color_lookup_160AB[maria_GetColor(colors.by.color2)][maria_GetColor(colors.by.color3)];
}
}
}
}
else if(rmode == 2) // 320B/D
{
for(uint index = 0; index < MARIA_LINERAM_SIZE / 4; index++)
{
colors.color32 = * ptr++;
if(colors.color32 == 0)
{
* pix++ = bg32;
* pix++ = bg32;
}
else
{
if((colors.wo.color0 == 0))
{
* pix++ = bg32;
}
else
{
* pix++ = maria_GetColor(write_mode_lookup_mode2A[colors.by.color0]) |
maria_GetColor(write_mode_lookup_mode2B[colors.by.color0]) << 8 |
maria_GetColor(write_mode_lookup_mode2A[colors.by.color1]) << 16 |
maria_GetColor(write_mode_lookup_mode2B[colors.by.color1]) << 24;
}
if((colors.wo.color1 == 0))
{
* pix++ = bg32;
}
else
{
* pix++ = maria_GetColor(write_mode_lookup_mode2A[colors.by.color2]) |
maria_GetColor(write_mode_lookup_mode2B[colors.by.color2]) << 8 |
maria_GetColor(write_mode_lookup_mode2A[colors.by.color3]) << 16 |
maria_GetColor(write_mode_lookup_mode2B[colors.by.color3]) << 24;
}
}
}
}
else if(rmode == 3) // 320A/C
{
for(uint index = 0; index < MARIA_LINERAM_SIZE / 4; index++)
{
colors.color32 = * ptr++;
if(colors.color32 == 0)
{
* pix++ = bg32;
* pix++ = bg32;
}
else
{
* pix++ = maria_GetColor((colors.by.color0 & 30)) | (maria_GetColor(color_lookup_320AC[colors.by.color0]) << 8) | (maria_GetColor((colors.by.color1 & 30)) << 16) | (maria_GetColor(color_lookup_320AC[colors.by.color1]) << 24);
* pix++ = maria_GetColor((colors.by.color2 & 30)) | (maria_GetColor(color_lookup_320AC[colors.by.color2]) << 8) | (maria_GetColor((colors.by.color3 & 30)) << 16) | (maria_GetColor(color_lookup_320AC[colors.by.color3]) << 24);
}
}
}
// -------------------------------------------------------
// Composite Artifact handling - mainly for Tower Toppler
// -------------------------------------------------------
if(use_composite_filtering && ((rmode == 2) || (rmode == 3)))
{
if(maria_scanline > use_composite_filtering) // The scanline check here is a hack - don't like the blurred look of artifacting on the upper screen on Tower Toppler... and this gives us some speed!
{
u8 lum1 = 0x00;
u8 lum2 = buffer_local[0] & 0x0f;
u8 lum3 = buffer_local[1] & 0x0f;
for(u16 pixel = 2; pixel < (MARIA_LINERAM_SIZE * 2) - 1; pixel++)
{
lum1 = lum2;
lum2 = lum3;
lum3 = buffer_local[pixel] & 0x0f;
if((lum1 | lum3) == 0) // First order artifacting... DULL-BRIGHT-DULL
{
if(lum2 & 0xFC) // Some reasonably bright intensity... 4 and up
{
if(pixel & 1) // Ledges (slightly brighter)
{
// Although it appears we're looking at an 'odd' pixel, we are really hinging on lum2 which would be an 'even' pixel here - hence the brighter processing
buffer_local[pixel - 1] = ((buffer_local[pixel - 1] & 0xF0) | artifacting_lookup_bright[lum2]);
buffer_local[pixel - 2] = buffer_local[pixel - 1];
buffer_local[pixel - 0] = buffer_local[pixel - 1];
}
else // Wall Bricks
{
// Shift color hue - produces reasonable separation in odd/even pixel artifacting colors
buffer_local[pixel - 1] = ((buffer_local[pixel - 1] & 0xF0) | artifacting_lookup_dull[lum2]) + 0x20;
buffer_local[pixel - 2] = buffer_local[pixel - 1];
buffer_local[pixel - 0] = buffer_local[pixel - 1];
}
}
}
else if(lum1 == 0)
{
if((lum2 & 0xF8) && (lum3 & 0xF8)) // Second order artifacting... DULL-DULL-BRIGHT-BRIGHT-DULL - look for bright intensity here (8 and up)
{
if(((buffer_local[pixel + 1] & 0x0F) == 0) && ((buffer_local[pixel - 3] & 0x0F) == 0))
{
buffer_local[pixel - 2] = ((buffer_local[pixel - 1] & 0xF0) | artifacting_lookup_bright[lum2]);
}
}
}
}
}
}
if(use_composite_filtering) memcpy(buffer, buffer_local, MARIA_LINERAM_SIZE * 2);
}
// ==============================================================================
// Functions below this point read into the 7800 Cart Address Space... and must
// be handled differently for the new 'banksets' scheme - bankset versions of
// these functions can be found further down the source code...
// ==============================================================================
// ----------------------------------------------------------------------------
// StoreGraphic
// ----------------------------------------------------------------------------
static inline __attribute__((always_inline)) void maria_StoreGraphic()
{
byte data = memory_ram[maria_pp.w];
if(maria_wmode)
{
if(data) maria_StoreCellWriteMode(write_mode_lookup[data]);
}
else
{
if(data) maria_StoreCells4(data);
}
}
// ---------------------------------------------------------------------
// And this is the Kangaroo version that is a little slower to emulate.
// ---------------------------------------------------------------------
static inline __attribute__((always_inline)) void mariaROO_StoreGraphic()
{
byte data = memory_ram[maria_pp.w];
if(maria_wmode)
{
if(data) mariaROO_StoreCellWriteMode(write_mode_lookup[data]);
}
else
{
if(data) mariaROO_StoreCells4(data);
}
}
// ----------------------------------------------------------------------------
// StoreLineRAM - This is called quite often so do this as fast as possible.
// ----------------------------------------------------------------------------
ITCM_CODE static void maria_StoreLineRAM()
{
u16 index;
if(bRenderFrame) // If we are rendering frames...
{
u32 * ptr = (u32 * ) maria_lineRAM;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr = 0;
write_mask_low = ((memory_ram[CTRL] & 3)) ? 0x0F : 0x03;
write_mask_high = ((memory_ram[CTRL] & 3)) ? 0xF0 : 0x30;
}
maria_pp.b.l = memory_ram[maria_dp.w++];
uint mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++];
while((mode & 0x5f) && (maria_cycles < MARIA_CYCLE_LIMIT)) // Never chew up more cycles than the limit (return control to 6502)
{
u8 width;
u8 direct = 1;
if(mode & 31)
{
maria_cycles += MARIA_CYCLES_4_BYTE_HEADER; // Maria cycles (Header 4 byte)
maria_palette = (mode & 0xE0) >> 3;
maria_horizontal = memory_ram[maria_dp.w++];
width = (~mode & 31) + 1;
}
else
{
maria_cycles += MARIA_CYCLES_5_BYTE_HEADER; // Maria cycles (Header 5 byte)
maria_palette = (memory_ram[maria_dp.w] & 0xE0) >> 3;
width = memory_ram[maria_dp.w++] & 31;
width = (width == 0) ? 32 : ((~width) & 31) + 1;
maria_horizontal = memory_ram[maria_dp.w++];
if(mode & 32) direct = 0;
maria_wmode = mode & 128;
}
// Note: the DMA timing here is not perfect - but it's closer than it has been in the past. Good enough for handheld use.
u32 dma_holes = 0;
if(direct) // Are we DIRECT mode?
{
maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++)
{
if(maria_IsHoleyDMA()) dma_holes++; // Adjust for HoleyDMA
else if(bRenderFrame) maria_StoreGraphic(); // Render the graphic if not HoleyDMA
maria_horizontal += (maria_wmode ? 2 : 4); // Adjust the horizontal
maria_pp.w++; // And move to the next entry
}
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += (3 * (width - dma_holes)); // Maria cycles (Direct graphic read) - compensate for each holey DMA access
if(dma_holes) maria_cycles += 3; // And if there were any holey DMA accesses, we add 3 back for the DMA access
}
else // Indirect...
{
u8 cwidth = (memory_ram[CTRL] & 16);
lpair basePP = maria_pp;
u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8);
for(index = 0; index < width; index++)
{
maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++];
if(maria_IsHoleyDMA()) // Adjust for HoleyDMA
{
dma_holes++;
if(cwidth) maria_horizontal += (maria_wmode ? 2 : 4);
}
else if(bRenderFrame)
{
maria_StoreGraphic(); // Maria cycles (Indirect, 1 byte)
if(cwidth)
{
maria_pp.w++;
maria_horizontal += (maria_wmode ? 2 : 4);
maria_StoreGraphic(); // Maria cycles (Indirect, 2 bytes)
}
}
maria_horizontal += (maria_wmode ? 2 : 4);
}
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles)
if(dma_holes)
{
maria_cycles -= (((cwidth ? 9 : 6) * (dma_holes)) - 3);
}
}
maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this...
maria_pp.b.l = memory_ram[maria_dp.w++];
mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++];
}
}
// ----------------------------------------------------------------------------
// StoreLineRAM - Kangaroo Mode version
// ----------------------------------------------------------------------------
ITCM_CODE static void mariaROO_StoreLineRAM()
{
u16 index;
if(bRenderFrame) // If we are rendering frames...
{
u32 * ptr = (u32 * ) maria_lineRAM;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr = 0;
write_mask_low = ((memory_ram[CTRL] & 3)) ? 0x0F : 0x03;
write_mask_high = ((memory_ram[CTRL] & 3)) ? 0xF0 : 0x30;
}
maria_pp.b.l = memory_ram[maria_dp.w++];
uint mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++];
while((mode & 0x5f) && (maria_cycles < MARIA_CYCLE_LIMIT)) // Never chew up more cycles than the limit (return control to 6502)
{
u8 width;
u8 direct = 1;
if(mode & 31)
{
maria_cycles += MARIA_CYCLES_4_BYTE_HEADER; // Maria cycles (Header 4 byte)
maria_palette = (mode & 0xE0) >> 3;
maria_horizontal = memory_ram[maria_dp.w++];
width = (~mode & 31) + 1;
}
else
{
maria_cycles += MARIA_CYCLES_5_BYTE_HEADER; // Maria cycles (Header 5 byte)
maria_palette = (memory_ram[maria_dp.w] & 0xE0) >> 3;
width = memory_ram[maria_dp.w++] & 31;
width = (width == 0) ? 32 : ((~width) & 31) + 1;
maria_horizontal = memory_ram[maria_dp.w++];
if(mode & 32) direct = 0;
maria_wmode = mode & 128;
}
// Note: the DMA timing here is not perfect - but it's closer than it has been in the past. Good enough for handheld use.
u32 dma_holes = 0;
if(direct) // Are we DIRECT mode?
{
maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++)
{
if(maria_IsHoleyDMA()) dma_holes++; // Adjust for HoleyDMA
else if(bRenderFrame) mariaROO_StoreGraphic(); // Render the graphic if not HoleyDMA
maria_horizontal += (maria_wmode ? 2 : 4); // Adjust the horizontal
maria_pp.w++; // And move to the next entry
}
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += (3 * (width - dma_holes)); // Maria cycles (Direct graphic read) - compensate for each holey DMA access
if(dma_holes) maria_cycles += 3; // And if there were any holey DMA accesses, we add 3 back for the DMA access
}
else // Indirect...
{
u8 cwidth = (memory_ram[CTRL] & 16);
lpair basePP = maria_pp;
u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8);
for(index = 0; index < width; index++)
{
maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++];
if(maria_IsHoleyDMA()) // Adjust for HoleyDMA
{
dma_holes++;
if(cwidth) maria_horizontal += (maria_wmode ? 2 : 4);
}
else if(bRenderFrame)
{
mariaROO_StoreGraphic(); // Maria cycles (Indirect, 1 byte)
if(cwidth)
{
maria_pp.w++;
maria_horizontal += (maria_wmode ? 2 : 4);
mariaROO_StoreGraphic(); // Maria cycles (Indirect, 2 bytes)
}
}
maria_horizontal += (maria_wmode ? 2 : 4);
}
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles)
if(dma_holes)
{
maria_cycles -= (((cwidth ? 9 : 6) * (dma_holes)) - 3);
}
}
maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this...
maria_pp.b.l = memory_ram[maria_dp.w++];
mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++];
}
}
// ----------------------------------------------------------------------------
// RenderScanline
// ----------------------------------------------------------------------------
ITCM_CODE void maria_RenderScanlineTOP(void)
{
maria_cycles = MARIA_CYCLES_DMA_INITIAL_COST; // Typical DMA startup cost
//
// Displays the background color when Maria is disabled (if applicable)
//
if((memory_ram[CTRL] & 96) != 64)
{
u32 * bgstart = (u32 * ) framePtr;
for(uint index = 0; index < MARIA_LINERAM_SIZE / 4; index++)
{
* bgstart++ = bg32;
}
framePtr += 256;
}
else
{
if(banksets_mask) return mariaBANK_RenderScanlineTOP();
maria_dpp.b.l = memory_ram[DPPL];
maria_dpp.b.h = memory_ram[DPPH];
u8 dl_mode = memory_ram[maria_dpp.w++];
maria_h8_h16 = ((uint) dl_mode << 6) & 0x1800;
maria_offset = dl_mode & 15;
maria_dp.b.h = memory_ram[maria_dpp.w];
maria_dp.b.l = memory_ram[maria_dpp.w + 1];
if(dl_mode & 128)
{
sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
maria_dp.b.h = memory_ram[maria_dpp.w + 0];
maria_dp.b.l = memory_ram[maria_dpp.w + 1];
}
if(memory_ram[CTRL] & 4) mariaROO_StoreLineRAM();
else maria_StoreLineRAM();
if(!maria_offset) // End of line?
{
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2;
u8 dl_mode = memory_ram[maria_dpp.w++];
maria_h8_h16 = ((uint) dl_mode << 6) & 0x1800;
maria_offset = dl_mode & 15;
if(dl_mode & 128)
{
sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
}
}
else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE;
}
}
}
ITCM_CODE void maria_RenderScanline(void)
{
maria_cycles = MARIA_CYCLES_DMA_INITIAL_COST; // Typical DMA startup cost
//
// Displays the background color when Maria is disabled (if applicable)
//
if((memory_ram[CTRL] & 96) != 64)
{
u32 * bgstart = (u32 * ) framePtr;
for(uint index = 0; index < MARIA_LINERAM_SIZE / 4; index++)
{
* bgstart++ = bg32;
}
}
else
{
if(banksets_mask) return mariaBANK_RenderScanline();
// This is where we render the video memory...
if(bRenderFrame) // If we are rendering frames...
{
maria_WriteLineRAM(framePtr);
framePtr += 256;
}
maria_dp.b.h = memory_ram[maria_dpp.w];
maria_dp.b.l = memory_ram[maria_dpp.w + 1];
if(memory_ram[CTRL] & 4) mariaROO_StoreLineRAM();
else maria_StoreLineRAM();
if(!maria_offset) // Last line?
{
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2;
u8 dl_mode = memory_ram[maria_dpp.w++];
maria_h8_h16 = ((uint) dl_mode << 6) & 0x1800;
maria_offset = dl_mode & 15;
if(dl_mode & 128)
{
sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
}
}
else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE;
}
}
}
// =======================================================================================
// BANKSET Handling
// We subsitutue out the maria_XXXX() calls with mariaBANK_XXXX() calls that will fetch
// non-system memory from the Maria portion of the banksets memory.
// =======================================================================================
extern byte banksets_memory[];
#define bankset_memory_read(address) banksets_memory[(address)]
// --------------------------------------------------------------------------------
// StoreGraphic using BANKSETS memory... It's a bit slower so we keep it separate.
// --------------------------------------------------------------------------------
static inline __attribute__((always_inline)) void mariaBANK_StoreGraphic()
{
byte data = bankset_memory_read(maria_pp.w);
if(maria_wmode)
{
if(data) maria_StoreCellWriteMode(write_mode_lookup[data]);
}
else
{
if(data) maria_StoreCells4(data);
}
}
// ----------------------------------------------------------------------------
// StoreLineRAM - BANKSETS memory version
// ----------------------------------------------------------------------------
static void mariaBANK_StoreLineRAM()
{
u16 index;
if(bRenderFrame) // If we are rendering frames...
{
u32 * ptr = (u32 * ) maria_lineRAM;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;
* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr++ = 0;* ptr = 0;
write_mask_low = ((memory_ram[CTRL] & 3)) ? 0x0F : 0x03;
write_mask_high = ((memory_ram[CTRL] & 3)) ? 0xF0 : 0x30;
}
maria_pp.b.l = memory_ram[maria_dp.w++];
uint mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++];
while((mode & 0x5f) && (maria_cycles < MARIA_CYCLE_LIMIT)) // Never chew up more cycles than the limit (return control to 6502)
{
u8 width;
u8 direct = 1;
if(mode & 31)
{
maria_cycles += MARIA_CYCLES_4_BYTE_HEADER; // Maria cycles (Header 4 byte)
maria_palette = (mode & 0xE0) >> 3;
maria_horizontal = memory_ram[maria_dp.w++];
width = (~mode & 31) + 1;
}
else
{
maria_cycles += MARIA_CYCLES_5_BYTE_HEADER; // Maria cycles (Header 5 byte)
maria_palette = (memory_ram[maria_dp.w] & 0xE0) >> 3;
width = memory_ram[maria_dp.w++] & 31;
width = (width == 0) ? 32 : ((~width) & 31) + 1;
maria_horizontal = memory_ram[maria_dp.w++];
if(mode & 32) direct = 0;
maria_wmode = mode & 128;
}
// Note: the DMA timing here is not perfect - but it's closer than it has been in the past. Good enough for handheld use.
u32 dma_holes = 0;
if(direct) // Are we DIRECT mode?
{
maria_pp.b.h += maria_offset;
for(index = 0; index < width; index++)
{
if(maria_IsHoleyDMA()) dma_holes++; // Adjust for HoleyDMA
else if(bRenderFrame) mariaBANK_StoreGraphic(); // Render the graphic if not HoleyDMA
maria_horizontal += (maria_wmode ? 2 : 4); // Adjust the horizontal
maria_pp.w++; // And move to the next entry
}
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += (3 * (width - dma_holes)); // Maria cycles (Direct graphic read) - compensate for each holey DMA access
if(dma_holes) maria_cycles += 3; // And if there were any holey DMA accesses, we add 3 back for the DMA access
}
else // Indirect...
{
u8 cwidth = (memory_ram[CTRL] & 16);
lpair basePP = maria_pp;
u16 charbase_plus_offset = ((maria_charbase + maria_offset) << 8);
for(index = 0; index < width; index++)
{
maria_pp.w = charbase_plus_offset | memory_ram[basePP.w++];
if(maria_IsHoleyDMA()) // Adjust for HoleyDMA
{
dma_holes++;
if(cwidth) maria_horizontal += (maria_wmode ? 2 : 4);
}
else if(bRenderFrame)
{
mariaBANK_StoreGraphic(); // Maria cycles (Indirect, 1 byte)
if(cwidth)
{
maria_pp.w++;
maria_horizontal += (maria_wmode ? 2 : 4);
mariaBANK_StoreGraphic(); // Maria cycles (Indirect, 2 bytes)
}
}
maria_horizontal += (maria_wmode ? 2 : 4);
}
maria_pp.w &= 0xFFFF; // Pole Position II and Failsafe both require that we wrap this...
maria_cycles += ((cwidth ? 9 : 6) * width); // Maria cycles for Indirect 1 byte (6 cycles) or 2 bytes (9 cycles)
if(dma_holes)
{
maria_cycles -= (((cwidth ? 9 : 6) * (dma_holes)) - 3);
}
}
maria_dp.w &= 0xFFFF; // Super Pac-Man requires that we wrap this...
maria_pp.b.l = memory_ram[maria_dp.w++];
mode = memory_ram[maria_dp.w++];
maria_pp.b.h = memory_ram[maria_dp.w++];
}
}
void mariaBANK_RenderScanlineTOP(void)
{
maria_dpp.b.l = bankset_memory_read(DPPL);
maria_dpp.b.h = bankset_memory_read(DPPH);
u8 dl_mode = bankset_memory_read(maria_dpp.w++);
maria_h8_h16 = ((uint) dl_mode << 6) & 0x1800;
maria_offset = dl_mode & 15;
maria_dp.b.h = bankset_memory_read(maria_dpp.w);
maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1);
if(bankset_memory_read(maria_dpp.w) & 128)
{
sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
maria_dp.b.h = bankset_memory_read(maria_dpp.w);
maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1);
}
mariaBANK_StoreLineRAM();
if(!maria_offset) // Last line?
{
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2;
u8 dl_mode = bankset_memory_read(maria_dpp.w++);
maria_h8_h16 = ((uint) dl_mode << 6) & 0x1800;
maria_offset = dl_mode & 15;
if(dl_mode & 128)
{
sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
}
}
else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE;
}
}
void mariaBANK_RenderScanline(void)
{
// This is where we render the video memory...
if(bRenderFrame) // If we are rendering frames...
{
maria_WriteLineRAM(framePtr);
framePtr += 256;
}
maria_dp.b.h = bankset_memory_read(maria_dpp.w);
maria_dp.b.l = bankset_memory_read(maria_dpp.w + 1);
mariaBANK_StoreLineRAM();
if(!maria_offset) // Last line?
{
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_LAST_LINE_ZONE;
maria_dpp.w += 2;
u8 dl_mode = bankset_memory_read(maria_dpp.w++);
maria_h8_h16 = ((uint) dl_mode << 6) & 0x1800;
maria_offset = dl_mode & 15;
if(dl_mode & 128)
{
sally_ExecuteNMI();
maria_cycles += MARIA_CYCLES_NMI_COST;
}
}
else
{
maria_offset--;
maria_cycles += MARIA_CYCLES_STARTUP_SHUTDOWN_OTHER_LINES_ZONE; // Maria cycles (Startup+Shutdown Other lines of zone) - Techncially 16 but we know we're over estimating so....
}
}
/* End of file */