mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
Added two TV Games (not working), and improved SPG110 SoC emulation. (#13153)
* machine/spg110.cpp: Improved interrupt emulation. * machine/spg110_video.cpp: Hooked up Y flip, cleaned up code, updated comments. New systems marked not working ------------------------------- JAKKS Pacific Inc / HotGen Ltd Bob the Builder - Project: Build It (JAKKS Pacific TV Game) (JUN 2 2006 14:42:01) [David Haywood, TeamEurope] JAKKS Pacific Inc / Digital Eclipse EA Sports Classics: NHL 95 & FIFA Soccer 96 (JAKKS Pacific TV Game) [David Haywood, TeamEurope]
This commit is contained in:
parent
026836d8cf
commit
a278e24cfd
@ -30,8 +30,7 @@ spg110_device::spg110_device(const machine_config &mconfig, device_type type, co
|
||||
m_portb_in(*this, 0),
|
||||
m_portc_in(*this, 0),
|
||||
m_adc_in(*this, 0x0fff),
|
||||
m_chip_sel(*this),
|
||||
m_is_spiderman(false)
|
||||
m_chip_sel(*this)
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,14 +45,47 @@ void spg110_device::videoirq_w(int state)
|
||||
set_state_unsynced(UNSP_IRQ0_LINE, state);
|
||||
}
|
||||
|
||||
void spg110_device::timerirq_w(int state)
|
||||
{
|
||||
set_state_unsynced(UNSP_IRQ3_LINE, state);
|
||||
}
|
||||
|
||||
void spg110_device::uartirq_w(int state)
|
||||
{
|
||||
set_state_unsynced(UNSP_IRQ4_LINE, state);
|
||||
}
|
||||
|
||||
void spg110_device::extirq_w(int state)
|
||||
{
|
||||
// External Int1 is IRQ4 (was 5 on SPG2xx)
|
||||
// External Int2 is IRQ2 (was 5 on SPG2xx)
|
||||
set_state_unsynced(UNSP_IRQ4_LINE, state);
|
||||
}
|
||||
|
||||
void spg110_device::ffreq1_w(int state)
|
||||
{
|
||||
set_state_unsynced(UNSP_IRQ5_LINE, state);
|
||||
}
|
||||
|
||||
void spg110_device::ffreq2_w(int state)
|
||||
{
|
||||
set_state_unsynced(UNSP_IRQ6_LINE, state);
|
||||
}
|
||||
|
||||
// notes about IRQ differences from 2xx
|
||||
//
|
||||
// TMB1 / TMB2 are IRQ7 (same as SPG2xx)
|
||||
// Key Change is IRQ4 (was 7 on SPG2xx)
|
||||
// LVD (Low Voltage Reset) is IRQ6 (doesn't exist on SPG2xx?)
|
||||
// ADC is IRQ1 (was 3 on SPG2xx)
|
||||
//
|
||||
// on SPG2xx 0x3D2E can redirect any other interrupt to the FIQ
|
||||
// on SPG110 FIQ is always from SPUIRQ (sound)
|
||||
//
|
||||
// on SPG2xx SPU_Ch_Irq (sound) is IRQ1, and SPU_Env_Irq / SPU_Beat_Irq is IRQ4
|
||||
// SPU_Ch_Irq / SPU_Env_Irq and SPU_Beat_Irq don't exist on SPG110? (assume SPU_Ch_Irq is SPUIRQ?)
|
||||
//
|
||||
// SPG2xx has SPI Interrupt on IRQ3, no SPI interrupt on SPG110?
|
||||
|
||||
void spg110_device::configure_spg_io(spg2xx_io_device* io)
|
||||
{
|
||||
@ -69,9 +101,9 @@ void spg110_device::configure_spg_io(spg2xx_io_device* io)
|
||||
io->adc_in<3>().set(FUNC(spg110_device::adc_r<3>));
|
||||
io->chip_select().set(FUNC(spg110_device::cs_w));
|
||||
// io->pal_read_callback().set(FUNC(spg110_device::get_pal_r));
|
||||
// io->write_timer_irq_callback().set(FUNC(spg110_device::timerirq_w));
|
||||
// io->write_uart_adc_irq_callback().set(FUNC(spg110_device::uartirq_w));
|
||||
// io->write_external_irq_callback().set(FUNC(spg110_device::extirq_w));
|
||||
io->write_timer_irq_callback().set(FUNC(spg110_device::timerirq_w));
|
||||
io->write_uart_adc_irq_callback().set(FUNC(spg110_device::uartirq_w));
|
||||
io->write_external_irq_callback().set(FUNC(spg110_device::extirq_w));
|
||||
io->write_ffrq_tmr1_irq_callback().set(FUNC(spg110_device::ffreq1_w));
|
||||
io->write_ffrq_tmr2_irq_callback().set(FUNC(spg110_device::ffreq2_w));
|
||||
}
|
||||
@ -112,49 +144,48 @@ void spg110_device::internal_map(address_map &map)
|
||||
map(0x002010, 0x002015).rw(m_spg_video, FUNC(spg110_video_device::tmap0_regs_r), FUNC(spg110_video_device::tmap0_regs_w));
|
||||
map(0x002016, 0x00201b).rw(m_spg_video, FUNC(spg110_video_device::tmap1_regs_r), FUNC(spg110_video_device::tmap1_regs_w));
|
||||
|
||||
#if 1 // more vregs?
|
||||
map(0x00201c, 0x00201c).w(m_spg_video, FUNC(spg110_video_device::spg110_201c_w));
|
||||
map(0x00201c, 0x00201c).w(m_spg_video, FUNC(spg110_video_device::vcomp_val_201c_w)); // P_VComp_Value (vertical compression)
|
||||
|
||||
map(0x002020, 0x002020).w(m_spg_video, FUNC(spg110_video_device::spg110_2020_w));
|
||||
map(0x002020, 0x002027).w(m_spg_video, FUNC(spg110_video_device::segment_202x_w)); // P_Segment0-7 (tilebases)
|
||||
map(0x002028, 0x002028).rw(m_spg_video, FUNC(spg110_video_device::adr_mode_2028_r), FUNC(spg110_video_device::adr_mode_2028_w)); // P_Adr_mode
|
||||
map(0x002029, 0x002029).rw(m_spg_video, FUNC(spg110_video_device::ext_bus_2029_r), FUNC(spg110_video_device::ext_bus_2029_w)); // P_Ext_Bus
|
||||
// 0x202a // P_Blending
|
||||
|
||||
map(0x002028, 0x002028).rw(m_spg_video, FUNC(spg110_video_device::spg110_2028_r), FUNC(spg110_video_device::spg110_2028_w));
|
||||
map(0x002029, 0x002029).rw(m_spg_video, FUNC(spg110_video_device::spg110_2029_r), FUNC(spg110_video_device::spg110_2029_w));
|
||||
// 0x2030 // P_Eff_color
|
||||
map(0x002031, 0x002031).w(m_spg_video, FUNC(spg110_video_device::win_mask_1_2031_w)); // P_Win_mask1 - sometimes 14a?
|
||||
map(0x002032, 0x002032).w(m_spg_video, FUNC(spg110_video_device::win_mask_2_2032_w)); // P_Win_mask2 - always 14a?
|
||||
map(0x002033, 0x002033).w(m_spg_video, FUNC(spg110_video_device::win_attribute_w)); // P_Win_attrribute
|
||||
map(0x002034, 0x002034).w(m_spg_video, FUNC(spg110_video_device::win_mask_3_2034_w)); // P_Win_mask3
|
||||
map(0x002035, 0x002035).w(m_spg_video, FUNC(spg110_video_device::win_mask_4_2035_w)); // P_Win_mask4
|
||||
map(0x002036, 0x002036).w(m_spg_video, FUNC(spg110_video_device::irq_tm_v_2036_w)); // P_IRQTMV
|
||||
map(0x002037, 0x002037).rw(m_spg_video, FUNC(spg110_video_device::irq_tm_h_2037_r), FUNC(spg110_video_device::irq_tm_h_2037_w)); // P_IRQTMH
|
||||
// 0x2038 // P_Effect_color (not the same as 2030)
|
||||
map(0x002039, 0x002039).w(m_spg_video, FUNC(spg110_video_device::effect_control_2039_w)); // P_Effect_control
|
||||
// 0x203a // P_Mix_offset
|
||||
// 0x203b // P_Fan_effect_th
|
||||
map(0x00203c, 0x00203c).w(m_spg_video, FUNC(spg110_video_device::huereference_203c_w)); // P_203C_HueRefer (should be set based on PAL/NTSC)
|
||||
map(0x00203d, 0x00203d).w(m_spg_video, FUNC(spg110_video_device::lum_adjust_203d_w)); // P_Lum_Adjust
|
||||
// 0x203e // P_LPVPosition
|
||||
// 0x203f // P_LPHPosition
|
||||
|
||||
map(0x002031, 0x002031).w(m_spg_video, FUNC(spg110_video_device::spg110_2031_w)); // sometimes 14a?
|
||||
map(0x002032, 0x002032).w(m_spg_video, FUNC(spg110_video_device::spg110_2032_w)); // always 14a?
|
||||
map(0x002033, 0x002033).w(m_spg_video, FUNC(spg110_video_device::spg110_2033_w));
|
||||
map(0x002034, 0x002034).w(m_spg_video, FUNC(spg110_video_device::spg110_2034_w));
|
||||
map(0x002035, 0x002035).w(m_spg_video, FUNC(spg110_video_device::spg110_2035_w));
|
||||
map(0x002036, 0x002036).w(m_spg_video, FUNC(spg110_video_device::spg110_2036_w)); // possible scroll register?
|
||||
map(0x002037, 0x002037).rw(m_spg_video, FUNC(spg110_video_device::spg110_2037_r), FUNC(spg110_video_device::spg110_2037_w));
|
||||
map(0x002042, 0x002042).rw(m_spg_video, FUNC(spg110_video_device::sp_control_2042_r),FUNC(spg110_video_device::sp_control_2042_w)); // P_Sp_control
|
||||
|
||||
map(0x002039, 0x002039).w(m_spg_video, FUNC(spg110_video_device::spg110_2039_w));
|
||||
map(0x002045, 0x002045).w(m_spg_video, FUNC(spg110_video_device::spg110_2045_w)); // not documented?
|
||||
|
||||
map(0x00203c, 0x00203c).w(m_spg_video, FUNC(spg110_video_device::spg110_203c_w));
|
||||
map(0x002050, 0x00205f).ram().w(m_spg_video, FUNC(spg110_video_device::transparent_color_205x_w)).share("spg_video:palctrlram"); // P_Trptcolor0 - 15
|
||||
|
||||
map(0x00203d, 0x00203d).w(m_spg_video, FUNC(spg110_video_device::spg110_203d_w)); // possible scroll register?
|
||||
map(0x002060, 0x002060).w(m_spg_video, FUNC(spg110_video_device::dma_dst_2060_w)); // P_DMA_Target_adr
|
||||
map(0x002061, 0x002061).w(m_spg_video, FUNC(spg110_video_device::dma_dst_seg_2061_w)); // P_DMA_Target_seg
|
||||
map(0x002062, 0x002062).rw(m_spg_video, FUNC(spg110_video_device::dma_len_status_2062_r),FUNC(spg110_video_device::dma_len_trigger_2062_w)); // P_DMA_numbr
|
||||
map(0x002063, 0x002063).rw(m_spg_video, FUNC(spg110_video_device::spg110_2063_r),FUNC(spg110_video_device::spg110_2063_w)); // P_DMA_control - Video IRQ source / ack (3 different things checked here instead of 2 on spg2xx?)
|
||||
map(0x002064, 0x002064).w(m_spg_video, FUNC(spg110_video_device::dma_dst_step_2064_w)); // P_DMA_Target_step
|
||||
map(0x002065, 0x002065).rw(m_spg_video, FUNC(spg110_video_device::dma_manual_2065_r), FUNC(spg110_video_device::dma_manual_2065_w)); // P_DMA_data
|
||||
map(0x002066, 0x002066).w(m_spg_video, FUNC(spg110_video_device::dma_source_2066_w)); // P_DMA_Source_adr
|
||||
map(0x002067, 0x002067).w(m_spg_video, FUNC(spg110_video_device::dma_source_seg_2067_w)); // P_DMA_Source_seg
|
||||
map(0x002068, 0x002068).rw(m_spg_video, FUNC(spg110_video_device::dma_src_step_2068_r), FUNC(spg110_video_device::dma_src_step_2068_w)); // P_DMA_Source_step
|
||||
|
||||
map(0x002042, 0x002042).rw(m_spg_video, FUNC(spg110_video_device::spg110_2042_r),FUNC(spg110_video_device::spg110_2042_w));
|
||||
|
||||
map(0x002045, 0x002045).w(m_spg_video, FUNC(spg110_video_device::spg110_2045_w));
|
||||
#endif
|
||||
|
||||
// seems to be 16 entries for.. something? on jak_capb these seem connected to the palette DMA operations, 0x2050 for 0x8000, 0x2051 for 0x8020, 0x2052 for 0x8040 etc. maybe 1 bit per pen?
|
||||
map(0x002050, 0x00205f).ram().w(m_spg_video, FUNC(spg110_video_device::spg110_205x_w)).share("spg_video:palctrlram");
|
||||
|
||||
// everything (dma? and interrupt flag?!)
|
||||
map(0x002060, 0x002060).w(m_spg_video, FUNC(spg110_video_device::dma_dst_w));
|
||||
map(0x002061, 0x002061).w(m_spg_video, FUNC(spg110_video_device::dma_unk_2061_w));
|
||||
map(0x002062, 0x002062).rw(m_spg_video, FUNC(spg110_video_device::dma_len_status_r),FUNC(spg110_video_device::dma_len_trigger_w));
|
||||
map(0x002063, 0x002063).rw(m_spg_video, FUNC(spg110_video_device::spg110_2063_r),FUNC(spg110_video_device::spg110_2063_w)); // Video IRQ source / ack (3 different things checked here instead of 2 on spg2xx?)
|
||||
map(0x002064, 0x002064).w(m_spg_video, FUNC(spg110_video_device::dma_dst_step_w));
|
||||
map(0x002065, 0x002065).rw(m_spg_video, FUNC(spg110_video_device::dma_manual_r), FUNC(spg110_video_device::dma_manual_w));
|
||||
map(0x002066, 0x002066).w(m_spg_video, FUNC(spg110_video_device::dma_src_w));
|
||||
map(0x002067, 0x002067).w(m_spg_video, FUNC(spg110_video_device::dma_unk_2067_w));
|
||||
map(0x002068, 0x002068).w(m_spg_video, FUNC(spg110_video_device::dma_src_step_w));
|
||||
|
||||
map(0x002100, 0x0021ff).ram(); // jak_spdmo only
|
||||
map(0x002200, 0x0022ff).ram(); // looks like per-pen brightness or similar? strange because palette isn't memory mapped here (maybe rowscroll?)
|
||||
map(0x002100, 0x0021ff).ram(); // P_Tx_Hvoffset0 - P_Tx_Hvoffset255 // rowscroll table
|
||||
map(0x002200, 0x0022ff).ram(); // P_HComp_Value0 - P_HComp_Value255 // horizontal compression table
|
||||
|
||||
/// sound registers? seems to be 8 long entries, only uses up to 0x7f? (register mapping seems similar to spg2xx, maybe with less channels?)
|
||||
map(0x003000, 0x00307f).rw(m_spg_audio, FUNC(spg110_audio_device::audio_r), FUNC(spg110_audio_device::audio_w));
|
||||
@ -162,7 +193,6 @@ void spg110_device::internal_map(address_map &map)
|
||||
|
||||
map(0x003100, 0x00310f).rw(m_spg_audio, FUNC(spg110_audio_device::audio_ctrl_r), FUNC(spg2xx_audio_device::audio_ctrl_w));
|
||||
|
||||
|
||||
// 0032xx looks like it could be the same as 003d00 on spg2xx
|
||||
map(0x003200, 0x00322f).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w));
|
||||
}
|
||||
@ -171,6 +201,4 @@ void spg110_device::internal_map(address_map &map)
|
||||
void spg110_device::device_reset()
|
||||
{
|
||||
unsp_device::device_reset();
|
||||
|
||||
m_spg_video->set_video_irq_spidman(m_is_spiderman);
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ public:
|
||||
m_screen.set_tag(std::forward<T>(screen_tag));
|
||||
}
|
||||
|
||||
void set_video_irq_spidman(bool is_spiderman) { m_is_spiderman = is_spiderman; }
|
||||
|
||||
auto porta_out() { return m_porta_out.bind(); }
|
||||
auto portb_out() { return m_portb_out.bind(); }
|
||||
auto portc_out() { return m_portc_out.bind(); }
|
||||
@ -79,6 +77,9 @@ private:
|
||||
void portb_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_portb_out(offset, data, mem_mask); }
|
||||
void portc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_portc_out(offset, data, mem_mask); }
|
||||
|
||||
void timerirq_w(int state);
|
||||
void uartirq_w(int state);
|
||||
void extirq_w(int state);
|
||||
void ffreq1_w(int state);
|
||||
void ffreq2_w(int state);
|
||||
|
||||
@ -88,7 +89,6 @@ private:
|
||||
void configure_spg_io(spg2xx_io_device* io);
|
||||
|
||||
void videoirq_w(int state);
|
||||
bool m_is_spiderman;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SPG110, spg110_device)
|
||||
|
@ -38,17 +38,12 @@ void spg110_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_
|
||||
|
||||
uint32_t nc = (bpp + 1) << 1;
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 0x03: pal = 0; break; // 8 bpp
|
||||
case 0x02: pal &=0x03; break; // 6 bpp
|
||||
case 0x01: break; // 4 bpp
|
||||
case 0x00: break; // 2 bpp
|
||||
}
|
||||
|
||||
uint32_t palette_offset = pal;
|
||||
|
||||
palette_offset <<= nc;
|
||||
if (bpp == 3)
|
||||
palette_offset = 0;
|
||||
|
||||
palette_offset <<= 4;
|
||||
|
||||
uint32_t bits_per_row = nc * w / 16;
|
||||
uint32_t words_per_tile = bits_per_row * h;
|
||||
@ -81,7 +76,7 @@ void spg110_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_
|
||||
}
|
||||
nbits -= nc;
|
||||
|
||||
uint32_t pal = palette_offset + (bits >> 16);
|
||||
uint8_t pennum = (palette_offset + (bits >> 16));
|
||||
bits &= 0xffff;
|
||||
|
||||
xx &= 0x01ff;
|
||||
@ -92,14 +87,14 @@ void spg110_video_device::draw(const rectangle &cliprect, uint32_t line, uint32_
|
||||
{
|
||||
int pix_index = xx + y_index;
|
||||
const pen_t *pens = m_palette->pens();
|
||||
uint32_t paldata = pens[pal];
|
||||
uint32_t paldata = pens[pennum];
|
||||
|
||||
int transmap = m_palctrlram[(pal & 0xf0)>>4];
|
||||
int transmap = m_palctrlram[(pennum & 0xf0)>>4];
|
||||
|
||||
bool trans = false;
|
||||
|
||||
if (transmap & 0x10) // maybe values other than 0x010 have other meanings, like blending?
|
||||
if ((pal & 0x0f) == (transmap & 0xf))
|
||||
if ((pennum & 0x0f) == (transmap & 0xf))
|
||||
trans = true;
|
||||
|
||||
if (!trans)
|
||||
@ -129,11 +124,12 @@ void spg110_video_device::draw_page(const rectangle &cliprect, uint32_t scanline
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
uint8_t bpp = attr & 0x03;
|
||||
|
||||
uint32_t tile_h = 8 << ((attr & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
uint32_t tile_w = 8 << ((attr & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
uint8_t bpp = (attr & 0x0003);
|
||||
// flip 0x000c
|
||||
uint32_t tile_w = 8 << ((attr & 0x0030) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
uint32_t tile_h = 8 << ((attr & 0x00c0) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
uint8_t pal = (attr & 0x0f00)>>8;
|
||||
uint8_t pri = (attr & 0x3000)>>12;
|
||||
|
||||
uint32_t tile_count_x = 512 / tile_w;
|
||||
|
||||
@ -151,9 +147,8 @@ void spg110_video_device::draw_page(const rectangle &cliprect, uint32_t scanline
|
||||
if (!tile)
|
||||
continue;
|
||||
|
||||
uint8_t pal = 0x000;
|
||||
uint8_t pri = 0x00;
|
||||
bool flip_x = false;
|
||||
bool flip_y = false;
|
||||
|
||||
if (!(ctrl & 0x0002)) // 'regset'
|
||||
{
|
||||
@ -167,15 +162,17 @@ void spg110_video_device::draw_page(const rectangle &cliprect, uint32_t scanline
|
||||
pal = extra_attribute & 0x0f;
|
||||
pri = (extra_attribute & 0x30) >> 4;
|
||||
flip_x = extra_attribute & 0x40;
|
||||
flip_y = extra_attribute & 0x80;
|
||||
}
|
||||
|
||||
const uint32_t yflipmask = flip_y ? tile_h - 1 : 0;
|
||||
|
||||
if (pri == priority)
|
||||
{
|
||||
|
||||
if (flip_x)
|
||||
draw<FlipXOn>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, 0, pal, tile_h, tile_w, bpp);
|
||||
draw<FlipXOn>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, yflipmask, pal, tile_h, tile_w, bpp);
|
||||
else
|
||||
draw<FlipXOff>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, 0, pal, tile_h, tile_w, bpp);
|
||||
draw<FlipXOff>(cliprect, tile_scanline, xx, yy, ctrl, bitmap_addr, tile, yflipmask, pal, tile_h, tile_w, bpp);
|
||||
}
|
||||
|
||||
}
|
||||
@ -184,7 +181,6 @@ void spg110_video_device::draw_page(const rectangle &cliprect, uint32_t scanline
|
||||
|
||||
void spg110_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr)
|
||||
{
|
||||
|
||||
// m_sprtileno tttt tttt tttt tttt t = tile number (all bits?)
|
||||
// m_sprattr1 xxxx xxxx yyyy yyyy x = low x bits, y = low y bits
|
||||
// m_sprattr2 YXzz pppp hhww fFbb X = high x bit, z = priority, p = palette, h = height, w = width, f = flipy, F = flipx, b = bpp, Y = high y bit
|
||||
@ -196,7 +192,7 @@ void spg110_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanli
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bitmap_addr = 0x40 * m_tilebase;
|
||||
uint32_t bitmap_addr = 0x40 * m_tilebase[0];
|
||||
uint16_t attr1 = m_sprattr1[base_addr];
|
||||
uint16_t attr2 = m_sprattr2[base_addr];
|
||||
|
||||
@ -212,8 +208,8 @@ void spg110_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanli
|
||||
if (!(attr2 & 0x8000))
|
||||
y+= 0x100;
|
||||
|
||||
const uint32_t h = 8 << ((attr2 & PAGE_TILE_HEIGHT_MASK) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
const uint32_t w = 8 << ((attr2 & PAGE_TILE_WIDTH_MASK) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
const uint32_t h = 8 << ((attr2 & 0x00c0) >> PAGE_TILE_HEIGHT_SHIFT);
|
||||
const uint32_t w = 8 << ((attr2 & 0x0030) >> PAGE_TILE_WIDTH_SHIFT);
|
||||
|
||||
// if (!(m_video_regs[0x42] & SPRITE_COORD_TL_MASK))
|
||||
// {
|
||||
@ -243,7 +239,7 @@ void spg110_video_device::draw_sprite(const rectangle &cliprect, uint32_t scanli
|
||||
//bool blend = (attr & 0x4000);
|
||||
const uint8_t bpp = attr2 & 0x0003;
|
||||
const uint32_t yflipmask = flip_y ? h - 1 : 0;
|
||||
const uint32_t palette_offset = (attr2 & 0x0f00) >> 8;
|
||||
uint32_t palette_offset = (attr2 & 0x0f00) >> 8;
|
||||
|
||||
if (pri == priority)
|
||||
{
|
||||
@ -341,88 +337,214 @@ device_memory_interface::space_config_vector spg110_video_device::memory_space_c
|
||||
}
|
||||
|
||||
|
||||
// irq source or similar?
|
||||
/* 0x2063 P_DMA_control
|
||||
despite the name this address is more IRQ control than DMA, although there are some DMA flags in here
|
||||
|
||||
bit15 bit14 bit13 bit12 bit11 bit10 bit9 bit8 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
|
||||
(unused) (unused) (unused) (unused) DMA_Busy wrtS readS testmd extsrc (unused) VDO_IRQ_Flag VDO_IRQ_EN BLK_IRQ_Flag BLK_IRQ_EN DMA_IRQ_Flag DMA_IRQ_EN
|
||||
|
||||
DMA_Busy - 0 = free, 1 = busy
|
||||
wrtS - used when writing 0x2065
|
||||
readS - used when reading 0x2065
|
||||
testmd - memory dump mode, causes data from dma_dst to be read in 0x2065?
|
||||
extsrc - 0 = work RAM, 1 = External Memory
|
||||
VDO_IRQ_Flag (aka TMc or VDO_IRQ) - Positional IRQ Status / Clear IRQ on write
|
||||
VDO_IRQ_EN (aka Tme) - Positional IRQ Enable
|
||||
BLK_IRQ_Flag - VBlank IRQ Status / Clear IRQ on write
|
||||
BLK_IRQ_EN - VBlank IRQ Enable
|
||||
DMA_IRQ_Flag - DMA IRQ Status / Clear IRQ on write (can also be cleared by starting a new DMA)
|
||||
DMA_IRQ_EN - DMA IRQ Enable
|
||||
|
||||
NOTE: if an IRQ flag is active when the IRQ Enable is turned on the IRQ will be taken
|
||||
writing 0 to IRQ enable does not clear IRQ flag
|
||||
|
||||
by default:
|
||||
BLK IRQ is asserted during the Vblank period, and deasserted when it ends
|
||||
DMA IRQ is asserted at the end of a DMA, and deasserted when a new one starts
|
||||
VDO IRQ is asserted when screen position in 2036 / 2037 is hit (has to be manually deasserted?)
|
||||
|
||||
*/
|
||||
|
||||
uint16_t spg110_video_device::spg110_2063_r()
|
||||
{
|
||||
// checks for bits 0x20 and 0x08 in the IRQ function (all IRQs point to the same place)
|
||||
// TODO these need to be handled properly
|
||||
uint8_t readS = 1;
|
||||
uint8_t wrtS = 1;
|
||||
uint8_t testmd = 0;
|
||||
uint8_t extsrc = 0;
|
||||
|
||||
// HACK! jak_spdo checks for 0x400 or 0x200 starting some of the games
|
||||
return m_video_irq_status | 0x0600; /* | 0x0002; */
|
||||
uint16_t ret = 0;
|
||||
|
||||
ret |= m_dma_irq_enable ? 0x0001 : 0x0000;
|
||||
ret |= m_dma_irq_flag ? 0x0002 : 0x0000;
|
||||
ret |= m_blk_irq_enable ? 0x0004 : 0x0000;
|
||||
ret |= m_blk_irq_flag ? 0x0008 : 0x0000;
|
||||
ret |= m_vdo_irq_enable ? 0x0010 : 0x0000;
|
||||
ret |= m_vdo_irq_flag ? 0x0020 : 0x0000;
|
||||
// 0x0040 unused
|
||||
ret |= extsrc ? 0x0080 : 0x0000;
|
||||
ret |= testmd ? 0x0100 : 0x0000;
|
||||
ret |= readS ? 0x0200 : 0x0000;
|
||||
ret |= wrtS ? 0x0400 : 0x0000;
|
||||
ret |= m_dma_busy ? 0x0800 : 0x0000;
|
||||
// 0x1000 unused
|
||||
// 0x2000 unused
|
||||
// 0x4000 unused
|
||||
// 0x8000 unused
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spg110_video_device::spg110_2063_w(uint16_t data)
|
||||
{
|
||||
// writes 0x28, probably clears the IRQ / IRQ sources? 0x63 is the same offset for this in spg2xx but bits used seem to be different
|
||||
const uint16_t old = m_video_irq_enable & m_video_irq_status;
|
||||
m_video_irq_status &= ~data;
|
||||
const uint16_t changed = old ^ (m_video_irq_enable & m_video_irq_status);
|
||||
if (changed)
|
||||
check_video_irq();
|
||||
m_dma_irq_enable = data & 0x01;
|
||||
m_blk_irq_enable = data & 0x04;
|
||||
m_vdo_irq_enable = data & 0x10;
|
||||
|
||||
if (data & 0x02)
|
||||
m_dma_irq_flag = 0;
|
||||
|
||||
if (data & 0x08)
|
||||
m_blk_irq_flag = 0;
|
||||
|
||||
if (data & 0x20)
|
||||
m_vdo_irq_flag = 0;
|
||||
|
||||
// still need to handle wrtS, readS, testmd, extsrc
|
||||
|
||||
update_video_irqs();
|
||||
}
|
||||
|
||||
|
||||
void spg110_video_device::spg110_201c_w(uint16_t data) { logerror("%s: 201c: %04x\n", machine().describe_context(), data); } // during startup text only
|
||||
void spg110_video_device::spg110_2020_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_tilebase); logerror("%s: 2020: %04x\n", machine().describe_context(), data); } // confirmed as tile base, seems to apply to both layers and sprites, unlike spg2xx which has separate registers
|
||||
void spg110_video_device::update_video_irqs()
|
||||
{
|
||||
bool irq_on = false;
|
||||
|
||||
void spg110_video_device::spg110_2028_w(uint16_t data) { logerror("%s: 2028: %04x\n", machine().describe_context(), data); } // startup
|
||||
uint16_t spg110_video_device::spg110_2028_r() { return 0x0000; }
|
||||
if ((m_blk_irq_enable) && (m_blk_irq_flag))
|
||||
irq_on = true;
|
||||
|
||||
void spg110_video_device::spg110_2029_w(uint16_t data) { logerror("%s: 2029: %04x\n", machine().describe_context(), data); } // 0006, 0008 on startup
|
||||
uint16_t spg110_video_device::spg110_2029_r() { return 0x0000; }
|
||||
if ((m_dma_irq_enable) && (m_dma_irq_flag))
|
||||
irq_on = true;
|
||||
|
||||
void spg110_video_device::spg110_2031_w(uint16_t data) { logerror("%s: 2031: %04x\n", machine().describe_context(), data); } // 014a or 0000 when ball is in trap
|
||||
void spg110_video_device::spg110_2032_w(uint16_t data) { logerror("%s: 2032: %04x\n", machine().describe_context(), data); } // 014a most of the time, 0000 very rarely
|
||||
void spg110_video_device::spg110_2033_w(uint16_t data) { logerror("%s: 2033: %04x\n", machine().describe_context(), data); } // changes, situational, eg when pausing
|
||||
void spg110_video_device::spg110_2034_w(uint16_t data) { logerror("%s: 2034: %04x\n", machine().describe_context(), data); } // 0141 on every scene transition
|
||||
void spg110_video_device::spg110_2035_w(uint16_t data) { logerror("%s: 2035: %04x\n", machine().describe_context(), data); } // 0141 on every scene transition
|
||||
void spg110_video_device::spg110_2036_w(offs_t offset, uint16_t data, uint16_t mem_mask) { logerror("%s: 2036: %04x\n", machine().describe_context(), data); COMBINE_DATA(&m_2036_scroll); } // seems related to ball y position, not scrolling (possibly shadow sprite related?)
|
||||
if ((m_vdo_irq_enable) && (m_vdo_irq_flag))
|
||||
irq_on = true;
|
||||
|
||||
uint16_t spg110_video_device::spg110_2037_r() { return 0x0000; } // added to something from the PRNG
|
||||
void spg110_video_device::spg110_2037_w(uint16_t data) { logerror("%s: 2037: %04x\n", machine().describe_context(), data); } // 0126 (always?)
|
||||
|
||||
void spg110_video_device::spg110_2039_w(uint16_t data) { logerror("%s: 2039: %04x\n", machine().describe_context(), data); } // 0803 on every scene transition
|
||||
|
||||
void spg110_video_device::spg110_203c_w(uint16_t data) { logerror("%s: 203c: %04x\n", machine().describe_context(), data); } // 0006 on startup, twice
|
||||
|
||||
void spg110_video_device::spg110_203d_w(uint16_t data) { logerror("%s: 203d: %04x\n", machine().describe_context(), data); } // changes, usually between scenes
|
||||
|
||||
uint16_t spg110_video_device::spg110_2042_r() { return 0x0000; }
|
||||
void spg110_video_device::spg110_2042_w(uint16_t data) { logerror("%s: 2042: %04x\n", machine().describe_context(), data); } // sets bit 0x0004, masks with 0xfffb etc.
|
||||
|
||||
void spg110_video_device::spg110_2045_w(uint16_t data) { logerror("%s: 2045: %04x\n", machine().describe_context(), data); } // 0006 on startup, once
|
||||
m_video_irq_cb(irq_on ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
void spg110_video_device::spg110_205x_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
|
||||
void spg110_video_device::vcomp_val_201c_w(uint16_t data) { logerror("%s: vcomp_val_201c_w: %04x\n", machine().describe_context(), data); } // during startup text only
|
||||
void spg110_video_device::segment_202x_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_tilebase[offset]); logerror("%s: segment/tilebase write: %02x %04x\n", machine().describe_context(), offset, data); } // confirmed as tile base, seems to apply to both layers and sprites, unlike spg2xx which has separate registers
|
||||
|
||||
void spg110_video_device::adr_mode_2028_w(uint16_t data) { logerror("%s: adr_mode_2028_w: %04x\n", machine().describe_context(), data); } // startup
|
||||
uint16_t spg110_video_device::adr_mode_2028_r() { return 0x0000; }
|
||||
|
||||
void spg110_video_device::ext_bus_2029_w(uint16_t data) { logerror("%s: ext_bus_2029_w: %04x\n", machine().describe_context(), data); } // 0006, 0008 on startup
|
||||
uint16_t spg110_video_device::ext_bus_2029_r() { return 0x0000; }
|
||||
|
||||
void spg110_video_device::win_mask_1_2031_w(uint16_t data) { logerror("%s: win_mask_1_2031_w: %04x\n", machine().describe_context(), data); } // 014a or 0000 when ball is in trap
|
||||
void spg110_video_device::win_mask_2_2032_w(uint16_t data) { logerror("%s: win_mask_2_2032_w: %04x\n", machine().describe_context(), data); } // 014a most of the time, 0000 very rarely
|
||||
void spg110_video_device::win_attribute_w(uint16_t data) { logerror("%s: win_attribute_w: %04x\n", machine().describe_context(), data); } // changes, situational, eg when pausing
|
||||
void spg110_video_device::win_mask_3_2034_w(uint16_t data) { logerror("%s: win_mask_3_2034_w: %04x\n", machine().describe_context(), data); } // 0141 on every scene transition
|
||||
void spg110_video_device::win_mask_4_2035_w(uint16_t data) { logerror("%s: win_mask_4_2035_w: %04x\n", machine().describe_context(), data); } // 0141 on every scene transition
|
||||
|
||||
void spg110_video_device::irq_tm_v_2036_w(uint16_t data)
|
||||
{
|
||||
// used for scanline raster effects, including ball shadow in capb
|
||||
m_tm_v_2036 = data & 0x1ff;
|
||||
update_raster_interrupt_timer();
|
||||
}
|
||||
|
||||
uint16_t spg110_video_device::irq_tm_h_2037_r()
|
||||
{
|
||||
// added to value from the PRNG for some random number generation cases
|
||||
// should this return the *current* horizontal position? or the register value written?
|
||||
return m_screen->hpos();
|
||||
}
|
||||
|
||||
void spg110_video_device::irq_tm_h_2037_w(uint16_t data)
|
||||
{
|
||||
// horizontal position for the scanline IRQ
|
||||
m_tm_h_2037 = data & 0x1ff;
|
||||
update_raster_interrupt_timer();
|
||||
}
|
||||
|
||||
void spg110_video_device::effect_control_2039_w(uint16_t data)
|
||||
{
|
||||
// 0803 on every scene transition
|
||||
logerror("%s: effect_control_2039_w: %04x\n", machine().describe_context(), data);
|
||||
}
|
||||
|
||||
void spg110_video_device::huereference_203c_w(uint16_t data)
|
||||
{
|
||||
// 0006 on startup, twice
|
||||
logerror("%s: huereference_203c_w: %04x\n", machine().describe_context(), data);
|
||||
}
|
||||
|
||||
void spg110_video_device::lum_adjust_203d_w(uint16_t data)
|
||||
{
|
||||
// changes, usually between scenes (brightness)
|
||||
logerror("%s: lum_adjust_203d_w: %04x\n", machine().describe_context(), data);
|
||||
}
|
||||
|
||||
uint16_t spg110_video_device::sp_control_2042_r()
|
||||
{
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
void spg110_video_device::sp_control_2042_w(uint16_t data)
|
||||
{
|
||||
// sets bit 0x0004, masks with 0xfffb etc.
|
||||
logerror("%s: sp_control_2042_w: %04x\n", machine().describe_context(), data);
|
||||
}
|
||||
|
||||
void spg110_video_device::spg110_2045_w(uint16_t data)
|
||||
{
|
||||
// 0006 on startup, once
|
||||
logerror("%s: spg110_2045_w: %04x\n", machine().describe_context(), data);
|
||||
}
|
||||
|
||||
void spg110_video_device::transparent_color_205x_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_palctrlram[offset]);
|
||||
}
|
||||
|
||||
void spg110_video_device::dma_dst_seg_2061_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_dst_seg); }
|
||||
void spg110_video_device::dma_dst_step_2064_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_dst_step); }
|
||||
void spg110_video_device::dma_source_seg_2067_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_src_seg); }
|
||||
void spg110_video_device::dma_src_step_2068_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_src_step); }
|
||||
uint16_t spg110_video_device::dma_src_step_2068_r(offs_t offset, uint16_t mem_mask) { return m_dma_src_step; }
|
||||
|
||||
void spg110_video_device::dma_unk_2061_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_unk_2061); }
|
||||
void spg110_video_device::dma_dst_step_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_dst_step); }
|
||||
void spg110_video_device::dma_unk_2067_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_src_high); }
|
||||
void spg110_video_device::dma_src_step_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_src_step); }
|
||||
void spg110_video_device::dma_dst_2060_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_dst); }
|
||||
void spg110_video_device::dma_source_2066_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_src); }
|
||||
|
||||
void spg110_video_device::dma_dst_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_dst); }
|
||||
void spg110_video_device::dma_src_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_dma_src); }
|
||||
|
||||
void spg110_video_device::dma_len_trigger_w(uint16_t data)
|
||||
void spg110_video_device::dma_len_trigger_2062_w(uint16_t data)
|
||||
{
|
||||
int length = data & 0x1fff;
|
||||
m_dma_irq_flag = 0;
|
||||
m_dma_busy = 1;
|
||||
update_video_irqs();
|
||||
|
||||
// this is presumably a counter that underflows to 0x1fff, because that's what the wait loop waits for?
|
||||
logerror("%s: (trigger len) %04x with values (unk) %04x (dststep) %04x (srchigh) %04x (src step) %04x | (dst) %04x (src) %04x\n", machine().describe_context(), data, m_dma_unk_2061, m_dma_dst_step, m_dma_src_high, m_dma_src_step, m_dma_dst, m_dma_src);
|
||||
logerror("%s: (trigger len) %04x with values (dstseg) %04x (dststep) %04x (srchigh) %04x (src step) %04x | (dst) %04x (src) %04x\n", machine().describe_context(), data, m_dma_dst_seg, m_dma_dst_step, m_dma_src_seg, m_dma_src_step, m_dma_dst, m_dma_src);
|
||||
|
||||
/*
|
||||
if (m_dma_unk_2061 != 0x0000)
|
||||
if (m_dma_dst_seg != 0x0000)
|
||||
{
|
||||
logerror("unknown DMA params are not zero!\n");
|
||||
}
|
||||
*/
|
||||
|
||||
int source = m_dma_src | m_dma_src_high << 16;
|
||||
int source = m_dma_src | m_dma_src_seg << 16;
|
||||
int dest = m_dma_dst;
|
||||
|
||||
// bits 0xc000 are 'DMABANK'
|
||||
// the use of other bits change slightly depending on them, for example
|
||||
// palette tranfsers only use the bottom 8 bits of dest, jak_bobb relies on this or bridge pieces have no palette
|
||||
if ((m_dma_dst & 0xc000) == 0x4000)
|
||||
dest &= 0x40ff;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
address_space &mem = m_cpu->space(AS_PROGRAM);
|
||||
@ -435,38 +557,28 @@ void spg110_video_device::dma_len_trigger_w(uint16_t data)
|
||||
}
|
||||
|
||||
// not sure, spiderman would suggest that some of these need to reset (unless a missing IRQ clears them)
|
||||
m_dma_unk_2061 = 0;
|
||||
m_dma_dst_seg = 0;
|
||||
//m_dma_dst_step = 0; // conyteni says no
|
||||
m_dma_src_high = 0;
|
||||
m_dma_src_seg = 0;
|
||||
//m_dma_src_step = 0; // conyteni says no
|
||||
m_dma_dst = 0;
|
||||
m_dma_src = 0;
|
||||
m_dma_dst = dest;
|
||||
m_dma_src = source;
|
||||
|
||||
// HACK: it really seems this interrupt status is related to the DMA, but jak_capb doesn't ack it, so must also be a way to disable it?
|
||||
if (m_is_spiderman)
|
||||
{
|
||||
const int i = 0x0002;
|
||||
|
||||
if (m_video_irq_enable & 1)
|
||||
{
|
||||
m_video_irq_status |= i;
|
||||
check_video_irq();
|
||||
}
|
||||
}
|
||||
m_dma_timer->adjust(attotime::from_usec(20));
|
||||
}
|
||||
|
||||
void spg110_video_device::dma_manual_w(uint16_t data)
|
||||
void spg110_video_device::dma_manual_2065_w(uint16_t data)
|
||||
{
|
||||
this->space(0).write_word(m_dma_dst * 2, data, 0xffff);
|
||||
}
|
||||
|
||||
uint16_t spg110_video_device::dma_manual_r()
|
||||
uint16_t spg110_video_device::dma_manual_2065_r()
|
||||
{
|
||||
uint16_t val = this->space(0).read_word(m_dma_dst * 2);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t spg110_video_device::dma_len_status_r()
|
||||
uint16_t spg110_video_device::dma_len_status_2062_r()
|
||||
{
|
||||
return 0x1fff; // DMA related?
|
||||
}
|
||||
@ -490,8 +602,6 @@ void spg110_video_device::tilemap_write_regs(int which, uint16_t* regs, int regn
|
||||
break;
|
||||
|
||||
case 0x2: // Page Attributes
|
||||
// 'priority' can't be priority here as it is on spg2xx, or the scores in attract will be behind the table, it really seems to be per attribute bit instead
|
||||
|
||||
logerror("video_w: Page %d Attributes = %04x (Priority:%d, Palette:%d, VSize:%d, HSize:%d, FlipY:%d, FlipX:%d, BPP:%d)\n", which, data
|
||||
, (data >> 12) & 3, (data >> 8) & 15, 8 << ((data >> 6) & 3), 8 << ((data >> 4) & 3), BIT(data, 3), BIT(data, 2), 2 * ((data & 3) + 1));
|
||||
regs[regno] = data;
|
||||
@ -530,14 +640,13 @@ void spg110_video_device::tmap1_regs_w(offs_t offset, uint16_t data)
|
||||
// this seems to be a different, non-cpu mapped space only accessible via the DMA?
|
||||
void spg110_video_device::map_video(address_map &map)
|
||||
{
|
||||
// are these addresses hardcoded, or can they move (in which case tilemap system isn't really suitable)
|
||||
map(0x00000, 0x03fff).ram(); // 2fff?
|
||||
map(0x00000, 0x02fff).ram();
|
||||
|
||||
map(0x04000, 0x041ff).ram().share("sprtileno"); // seems to be 3 blocks, almost certainly spritelist
|
||||
map(0x04000, 0x041ff).ram().share("sprtileno");
|
||||
map(0x04200, 0x043ff).ram().share("sprattr1");
|
||||
map(0x04400, 0x045ff).ram().share("sprattr2");
|
||||
|
||||
map(0x08000, 0x081ff).ram().w(FUNC(spg110_video_device::palette_w)).share("palram"); // palette format unknown
|
||||
map(0x08000, 0x081ff).ram().w(FUNC(spg110_video_device::palette_w)).share("palram");
|
||||
}
|
||||
|
||||
// Not used, for reference
|
||||
@ -690,26 +799,43 @@ void spg110_video_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_dma_src_step));
|
||||
save_item(NAME(m_dma_dst_step));
|
||||
save_item(NAME(m_dma_unk_2061));
|
||||
save_item(NAME(m_dma_src_high));
|
||||
save_item(NAME(m_dma_dst_seg));
|
||||
save_item(NAME(m_dma_src_seg));
|
||||
save_item(NAME(m_dma_dst));
|
||||
save_item(NAME(m_dma_src));
|
||||
save_item(NAME(m_bg_scrollx));
|
||||
save_item(NAME(m_bg_scrolly));
|
||||
save_item(NAME(m_2036_scroll));
|
||||
save_item(NAME(m_tm_v_2036));
|
||||
save_item(NAME(m_tm_h_2037));
|
||||
|
||||
save_item(NAME(m_blk_irq_enable));
|
||||
save_item(NAME(m_blk_irq_flag));
|
||||
save_item(NAME(m_dma_irq_enable));
|
||||
save_item(NAME(m_dma_irq_flag));
|
||||
save_item(NAME(m_vdo_irq_enable));
|
||||
save_item(NAME(m_vdo_irq_flag));
|
||||
|
||||
save_item(NAME(m_dma_busy));
|
||||
|
||||
m_screenpos_timer = timer_alloc(FUNC(spg110_video_device::screenpos_hit), this);
|
||||
m_screenpos_timer->adjust(attotime::never);
|
||||
|
||||
m_dma_timer = timer_alloc(FUNC(spg110_video_device::dma_done), this);
|
||||
m_dma_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
void spg110_video_device::device_reset()
|
||||
{
|
||||
m_dma_src_step = 0;
|
||||
m_dma_dst_step = 0;
|
||||
m_dma_unk_2061 = 0;
|
||||
m_dma_src_high = 0;
|
||||
m_dma_dst_seg = 0;
|
||||
m_dma_src_seg = 0;
|
||||
m_dma_dst = 0;
|
||||
m_dma_src = 0;
|
||||
m_bg_scrollx = 0;
|
||||
m_bg_scrolly = 0;
|
||||
m_2036_scroll = 0;
|
||||
m_tm_v_2036 = 0xffff;
|
||||
m_tm_h_2037 = 0xffff;
|
||||
|
||||
std::fill(std::begin(tmap0_regs), std::end(tmap0_regs), 0);
|
||||
std::fill(std::begin(tmap1_regs), std::end(tmap1_regs), 0);
|
||||
@ -717,6 +843,45 @@ void spg110_video_device::device_reset()
|
||||
// is there actually an enable register here?
|
||||
m_video_irq_enable = 0xffff;
|
||||
m_video_irq_status = 0x0000;
|
||||
|
||||
m_blk_irq_enable = 0;
|
||||
m_blk_irq_flag = 0;
|
||||
m_dma_irq_enable = 0;
|
||||
m_dma_irq_flag = 0;
|
||||
m_vdo_irq_enable = 0;
|
||||
m_vdo_irq_flag = 0;
|
||||
|
||||
m_dma_busy = 0;
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(spg110_video_device::dma_done)
|
||||
{
|
||||
m_dma_irq_flag = 1;
|
||||
m_dma_busy = 0;
|
||||
update_video_irqs();
|
||||
m_dma_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
void spg110_video_device::update_raster_interrupt_timer()
|
||||
{
|
||||
if (m_tm_h_2037 < 320 && m_tm_v_2036 < 240)
|
||||
{
|
||||
m_screenpos_timer->adjust(m_screen->time_until_pos(m_tm_v_2036, m_tm_h_2037));
|
||||
|
||||
}
|
||||
else
|
||||
m_screenpos_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(spg110_video_device::screenpos_hit)
|
||||
{
|
||||
m_vdo_irq_flag = 1;
|
||||
update_video_irqs();
|
||||
|
||||
m_screen->update_partial(m_screen->vpos());
|
||||
|
||||
// fire again (based on spg2xx logic)
|
||||
m_screenpos_timer->adjust(m_screen->time_until_pos(m_tm_v_2036, m_tm_h_2037));
|
||||
}
|
||||
|
||||
void spg110_video_device::palette_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
@ -727,27 +892,27 @@ void spg110_video_device::palette_w(offs_t offset, uint16_t data, uint16_t mem_m
|
||||
|
||||
uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
memset(&m_screenbuf[320 * cliprect.min_y], 0, 4 * 320 * ((cliprect.max_y - cliprect.min_y) + 1));
|
||||
|
||||
const uint32_t page1_addr = 0x40 * m_tilebase;//0x40 * m_video_regs[0x20];
|
||||
const uint32_t page2_addr = 0x40 * m_tilebase;//0x40 * m_video_regs[0x21];
|
||||
uint16_t *page1_regs = tmap0_regs;
|
||||
uint16_t *page2_regs = tmap1_regs;
|
||||
const pen_t *pens = m_palette->pens();
|
||||
const uint32_t page1_addr = 0x40 * m_tilebase[0];
|
||||
const uint32_t page2_addr = 0x40 * m_tilebase[0];
|
||||
|
||||
for (uint32_t scanline = (uint32_t)cliprect.min_y; scanline <= (uint32_t)cliprect.max_y; scanline++)
|
||||
{
|
||||
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
|
||||
m_screenbuf[(320 * scanline) + x] = pens[0];
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
draw_page(cliprect, scanline, i, page2_addr, page2_regs);
|
||||
draw_page(cliprect, scanline, i, page1_addr, page1_regs);
|
||||
draw_page(cliprect, scanline, i, page1_addr, tmap0_regs);
|
||||
draw_page(cliprect, scanline, i, page2_addr, tmap1_regs);
|
||||
draw_sprites(cliprect, scanline, i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
|
||||
{
|
||||
uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
|
||||
const uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
|
||||
uint32_t* dest = &bitmap.pix(y, cliprect.min_x);
|
||||
const uint32_t* src = &m_screenbuf[cliprect.min_x + 320 * y];
|
||||
std::copy_n(src, cliprect.width(), dest);
|
||||
}
|
||||
|
||||
@ -756,23 +921,6 @@ uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32
|
||||
|
||||
void spg110_video_device::vblank(int state)
|
||||
{
|
||||
const int i = 0x0008;
|
||||
|
||||
if (!state)
|
||||
{
|
||||
m_video_irq_status &= ~i;
|
||||
check_video_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_video_irq_enable & 1)
|
||||
{
|
||||
m_video_irq_status |= i;
|
||||
check_video_irq();
|
||||
}
|
||||
}
|
||||
|
||||
void spg110_video_device::check_video_irq()
|
||||
{
|
||||
m_video_irq_cb((m_video_irq_status & m_video_irq_enable) ? ASSERT_LINE : CLEAR_LINE);
|
||||
m_blk_irq_flag = state;
|
||||
update_video_irqs();
|
||||
}
|
||||
|
@ -27,58 +27,57 @@ public:
|
||||
m_screen.set_tag(std::forward<U>(screen_tag));
|
||||
}
|
||||
|
||||
void set_video_irq_spidman(bool is_spiderman) { m_is_spiderman = is_spiderman; }
|
||||
|
||||
void map_video(address_map &map) ATTR_COLD;
|
||||
|
||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
void vblank(int state);
|
||||
|
||||
void spg110_201c_w(uint16_t data);
|
||||
void spg110_2020_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void vcomp_val_201c_w(uint16_t data);
|
||||
void segment_202x_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
void spg110_2028_w(uint16_t data);
|
||||
void spg110_2029_w(uint16_t data);
|
||||
void adr_mode_2028_w(uint16_t data);
|
||||
void ext_bus_2029_w(uint16_t data);
|
||||
|
||||
uint16_t spg110_2028_r();
|
||||
uint16_t spg110_2029_r();
|
||||
uint16_t adr_mode_2028_r();
|
||||
uint16_t ext_bus_2029_r();
|
||||
|
||||
void spg110_2031_w(uint16_t data);
|
||||
void spg110_2032_w(uint16_t data);
|
||||
void spg110_2033_w(uint16_t data);
|
||||
void spg110_2034_w(uint16_t data);
|
||||
void spg110_2035_w(uint16_t data);
|
||||
void spg110_2036_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void spg110_2037_w(uint16_t data);
|
||||
void spg110_2039_w(uint16_t data);
|
||||
void win_mask_1_2031_w(uint16_t data);
|
||||
void win_mask_2_2032_w(uint16_t data);
|
||||
void win_attribute_w(uint16_t data);
|
||||
void win_mask_3_2034_w(uint16_t data);
|
||||
void win_mask_4_2035_w(uint16_t data);
|
||||
void irq_tm_v_2036_w(uint16_t data);
|
||||
void irq_tm_h_2037_w(uint16_t data);
|
||||
void effect_control_2039_w(uint16_t data);
|
||||
|
||||
void spg110_203c_w(uint16_t data);
|
||||
void spg110_203d_w(uint16_t data);
|
||||
void huereference_203c_w(uint16_t data);
|
||||
void lum_adjust_203d_w(uint16_t data);
|
||||
|
||||
void spg110_2042_w(uint16_t data);
|
||||
void sp_control_2042_w(uint16_t data);
|
||||
|
||||
void spg110_2045_w(uint16_t data);
|
||||
|
||||
void spg110_205x_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void transparent_color_205x_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
|
||||
uint16_t spg110_2037_r();
|
||||
uint16_t spg110_2042_r();
|
||||
uint16_t irq_tm_h_2037_r();
|
||||
uint16_t sp_control_2042_r();
|
||||
|
||||
void dma_dst_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_unk_2061_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_len_trigger_w(uint16_t data);
|
||||
void dma_dst_2060_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_dst_seg_2061_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_len_trigger_2062_w(uint16_t data);
|
||||
void spg110_2063_w(uint16_t data);
|
||||
void dma_dst_step_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_src_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_unk_2067_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_src_step_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_dst_step_2064_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_source_2066_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_source_seg_2067_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void dma_src_step_2068_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
uint16_t dma_src_step_2068_r(offs_t offset, uint16_t mem_mask);
|
||||
|
||||
uint16_t dma_len_status_r();
|
||||
uint16_t dma_len_status_2062_r();
|
||||
uint16_t spg110_2063_r();
|
||||
|
||||
uint16_t dma_manual_r();
|
||||
void dma_manual_w(uint16_t data);
|
||||
uint16_t dma_manual_2065_r();
|
||||
void dma_manual_2065_w(uint16_t data);
|
||||
|
||||
uint16_t tmap0_regs_r(offs_t offset);
|
||||
uint16_t tmap1_regs_r(offs_t offset);
|
||||
@ -105,9 +104,7 @@ private:
|
||||
|
||||
PAGE_PRIORITY_FLAG_MASK = 0x3000,
|
||||
PAGE_PRIORITY_FLAG_SHIFT = 12,
|
||||
PAGE_TILE_HEIGHT_MASK = 0x00c0,
|
||||
PAGE_TILE_HEIGHT_SHIFT = 6,
|
||||
PAGE_TILE_WIDTH_MASK = 0x0030,
|
||||
PAGE_TILE_WIDTH_SHIFT = 4,
|
||||
|
||||
TILE_X_FLIP = 0x0004,
|
||||
@ -140,21 +137,21 @@ private:
|
||||
|
||||
uint16_t m_dma_src_step;
|
||||
uint16_t m_dma_dst_step;
|
||||
uint16_t m_dma_unk_2061;
|
||||
uint16_t m_dma_src_high;
|
||||
uint16_t m_dma_dst_seg;
|
||||
uint16_t m_dma_src_seg;
|
||||
|
||||
uint16_t m_dma_dst;
|
||||
uint16_t m_dma_src;
|
||||
|
||||
uint16_t m_bg_scrollx;
|
||||
uint16_t m_bg_scrolly;
|
||||
uint16_t m_2036_scroll;
|
||||
uint16_t m_tm_v_2036;
|
||||
uint16_t m_tm_h_2037;
|
||||
|
||||
uint16_t m_tilebase;
|
||||
uint16_t m_tilebase[8];
|
||||
|
||||
uint16_t m_video_irq_enable;
|
||||
uint16_t m_video_irq_status;
|
||||
void check_video_irq();
|
||||
|
||||
void tilemap_write_regs(int which, uint16_t* regs, int regno, uint16_t data);
|
||||
|
||||
@ -164,8 +161,28 @@ private:
|
||||
void draw_sprite(const rectangle &cliprect, uint32_t scanline, int priority, uint32_t base_addr);
|
||||
void draw_sprites(const rectangle &cliprect, uint32_t scanline, int priority);
|
||||
|
||||
void update_raster_interrupt_timer();
|
||||
|
||||
TIMER_CALLBACK_MEMBER(screenpos_hit);
|
||||
TIMER_CALLBACK_MEMBER(dma_done);
|
||||
|
||||
void update_video_irqs();
|
||||
|
||||
uint8_t m_blk_irq_enable;
|
||||
uint8_t m_blk_irq_flag;
|
||||
|
||||
uint8_t m_dma_irq_enable;
|
||||
uint8_t m_dma_irq_flag;
|
||||
|
||||
uint8_t m_vdo_irq_enable;
|
||||
uint8_t m_vdo_irq_flag;
|
||||
|
||||
uint8_t m_dma_busy;
|
||||
|
||||
emu_timer *m_screenpos_timer;
|
||||
emu_timer *m_dma_timer;
|
||||
|
||||
uint32_t m_screenbuf[320 * 240];
|
||||
bool m_is_spiderman;
|
||||
|
||||
devcb_write_line m_video_irq_cb;
|
||||
};
|
||||
|
@ -45930,12 +45930,14 @@ pi_stry
|
||||
pi_stry2
|
||||
|
||||
@source:tvgames/spg110.cpp
|
||||
conyfght
|
||||
conyping //
|
||||
conyteni //
|
||||
easports
|
||||
jak_bobb
|
||||
jak_capb //
|
||||
jak_spdmo //
|
||||
jak_spdmoa
|
||||
conyteni //
|
||||
conyping //
|
||||
conyfght
|
||||
sstarkar
|
||||
|
||||
@source:tvgames/spg29x.cpp
|
||||
|
@ -12,10 +12,10 @@
|
||||
Conny TV Virtual Tennis
|
||||
Conny Ping Pong
|
||||
Conny TV Virtual Fighter
|
||||
JAKKS EA Sports (NHL 95 + Fifa 96) (EU)
|
||||
|
||||
assumed:
|
||||
JAKKS EA Sports (NHL 95 + Madden 95) (US)
|
||||
JAKKS EA Sports (NHL 95 + Fifa 96) (US)
|
||||
JAKKS Bob the Builder
|
||||
JAKKS Disney (original release)
|
||||
|
||||
@ -27,7 +27,10 @@
|
||||
#include "bus/generic/carts.h"
|
||||
|
||||
#include "cpu/unsp/unsp.h"
|
||||
|
||||
#include "machine/nvram.h"
|
||||
#include "machine/spg110.h"
|
||||
|
||||
#include "screen.h"
|
||||
#include "softlist_dev.h"
|
||||
#include "speaker.h"
|
||||
@ -45,7 +48,7 @@ public:
|
||||
{ }
|
||||
|
||||
void spg110_base(machine_config &config);
|
||||
void spg110_spdmo(machine_config& config);
|
||||
void spg110_base_pal(machine_config &config);
|
||||
|
||||
ioport_value plunger_r();
|
||||
|
||||
@ -56,6 +59,18 @@ protected:
|
||||
virtual void mem_map(address_map &map) ATTR_COLD;
|
||||
};
|
||||
|
||||
class spg110_easports_game_state : public spg110_game_state
|
||||
{
|
||||
public:
|
||||
spg110_easports_game_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
spg110_game_state(mconfig, type, tag)
|
||||
{ }
|
||||
void easports_pal(machine_config &config);
|
||||
|
||||
private:
|
||||
virtual void mem_map(address_map &map) override ATTR_COLD;
|
||||
};
|
||||
|
||||
class spg110_sstarkar_game_state : public spg110_game_state
|
||||
{
|
||||
public:
|
||||
@ -64,7 +79,7 @@ public:
|
||||
m_cart(*this, "cartslot"),
|
||||
m_cartrom(*this, "cartrom")
|
||||
{ }
|
||||
public:
|
||||
|
||||
void sstarkar(machine_config &config);
|
||||
|
||||
protected:
|
||||
@ -92,6 +107,14 @@ void spg110_sstarkar_game_state::mem_map_cart(address_map &map)
|
||||
map(0x004000, 0x0fffff).bankr("cartrom");
|
||||
}
|
||||
|
||||
void spg110_easports_game_state::mem_map(address_map &map)
|
||||
{
|
||||
//map(0x001000, 0x007fff).ram(); // ??
|
||||
map(0x004000, 0x2fffff).rom().region("maincpu", 0x8000);
|
||||
map(0x3e0000, 0x3effff).ram().share("nvram"); // size? is all of it backed up?
|
||||
map(0x3f0000, 0x3fffff).ram(); // seems to only be used for GFX data
|
||||
}
|
||||
|
||||
|
||||
static INPUT_PORTS_START( jak_capb )
|
||||
PORT_START("PA")
|
||||
@ -254,129 +277,8 @@ ioport_value spg110_game_state::plunger_r()
|
||||
}
|
||||
|
||||
|
||||
static INPUT_PORTS_START( jak_spdmo )
|
||||
PORT_START("PA")
|
||||
PORT_BIT( 0x001f, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("Menu / Pause")
|
||||
PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON4 )
|
||||
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON3 )
|
||||
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON2 )
|
||||
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON1 )
|
||||
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("Joypad Right")
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("Joypad Left")
|
||||
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("Joypad Down")
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Joypad Up")
|
||||
|
||||
PORT_START("PB")
|
||||
PORT_DIPNAME( 0x0001, 0x0000, "PB" )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0001, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0002, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0002, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0004, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0004, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0008, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0008, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0010, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0010, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0020, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0020, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0040, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0040, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0080, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0080, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0100, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0100, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0200, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0200, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0400, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0400, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0800, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0800, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x1000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x1000, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x2000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x2000, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x4000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x4000, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x8000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x8000, DEF_STR( On ) )
|
||||
|
||||
PORT_START("PC")
|
||||
PORT_DIPNAME( 0x0001, 0x0000, "PC" )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0001, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0002, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0002, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0004, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0004, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0008, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0008, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0010, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0010, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0020, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0020, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0040, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0040, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0080, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0080, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0100, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0100, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0200, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0200, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0400, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0400, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0800, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0800, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x1000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x1000, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x2000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x2000, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x4000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x4000, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x8000, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x8000, DEF_STR( On ) )
|
||||
|
||||
PORT_START("JOYX")
|
||||
|
||||
PORT_START("JOYY")
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
|
||||
static INPUT_PORTS_START( conyteni )
|
||||
static INPUT_PORTS_START( spg110_base )
|
||||
PORT_START("PA")
|
||||
PORT_DIPNAME( 0x0001, 0x0000, "PA" )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
@ -431,15 +333,27 @@ static INPUT_PORTS_START( conyteni )
|
||||
PORT_DIPNAME( 0x0001, 0x0000, "PB" )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0001, DEF_STR( On ) )
|
||||
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Console Back")
|
||||
PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Console Enter")
|
||||
PORT_DIPNAME( 0x0002, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0002, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0004, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0004, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0008, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0008, DEF_STR( On ) )
|
||||
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("Console Right")
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("Console Down")
|
||||
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("Console Left")
|
||||
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("Console Up")
|
||||
PORT_DIPNAME( 0x0010, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0010, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0020, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0020, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0040, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0040, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0080, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0080, DEF_STR( On ) )
|
||||
PORT_DIPNAME( 0x0100, 0x0000, DEF_STR( Unknown ) )
|
||||
PORT_DIPSETTING( 0x0000, DEF_STR( Off ) )
|
||||
PORT_DIPSETTING( 0x0100, DEF_STR( On ) )
|
||||
@ -518,7 +432,82 @@ static INPUT_PORTS_START( conyteni )
|
||||
PORT_START("JOYX")
|
||||
|
||||
PORT_START("JOYY")
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
static INPUT_PORTS_START( jak_spdmo )
|
||||
PORT_INCLUDE( spg110_base )
|
||||
|
||||
PORT_MODIFY("PA")
|
||||
PORT_BIT( 0x001f, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("Menu / Pause")
|
||||
PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON4 )
|
||||
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON3 )
|
||||
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON2 )
|
||||
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON1 )
|
||||
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("Joypad Right")
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("Joypad Left")
|
||||
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("Joypad Down")
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Joypad Up")
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START( jak_bobb )
|
||||
PORT_INCLUDE( spg110_base )
|
||||
|
||||
PORT_MODIFY("PA")
|
||||
PORT_BIT( 0x001f, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("Menu / Pause")
|
||||
PORT_BIT( 0x00c0, IP_ACTIVE_HIGH, IPT_UNUSED )
|
||||
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON1 )
|
||||
// not technically a joystick, so 2 opposing buttons could be pressed, but maps where Joystick usually maps
|
||||
// using PORT_16WAY for now like ksys573.cpp
|
||||
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("Right / Blue") PORT_16WAY
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("Left / Green") PORT_16WAY
|
||||
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("Down / Red") PORT_16WAY
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Up / Yellow") PORT_16WAY
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START( easports )
|
||||
PORT_INCLUDE( spg110_base )
|
||||
|
||||
PORT_MODIFY("PA")
|
||||
// not all units had 2 control pads
|
||||
// hold right and button 2 (B) on startup for ROM test
|
||||
PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
|
||||
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
|
||||
PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
|
||||
PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
|
||||
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(2) // START
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2) // B
|
||||
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) // A
|
||||
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) // C
|
||||
|
||||
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) // START
|
||||
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) // B
|
||||
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) // A
|
||||
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) // C
|
||||
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
|
||||
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
|
||||
|
||||
PORT_MODIFY("PC") // different configurations were hardwired, this can't be changed by the user
|
||||
PORT_CONFNAME(0x01, 0x00, "Pad Configuration")
|
||||
PORT_CONFSETTING(0x01, "Single")
|
||||
PORT_CONFSETTING(0x00, "Double")
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START( conyteni )
|
||||
PORT_INCLUDE( spg110_base )
|
||||
|
||||
PORT_MODIFY("PB")
|
||||
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Console Back")
|
||||
PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Console Enter")
|
||||
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("Console Right")
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("Console Down")
|
||||
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("Console Left")
|
||||
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("Console Up")
|
||||
INPUT_PORTS_END
|
||||
|
||||
void spg110_game_state::spg110_base(machine_config &config)
|
||||
@ -544,13 +533,21 @@ void spg110_game_state::spg110_base(machine_config &config)
|
||||
m_maincpu->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
|
||||
}
|
||||
|
||||
void spg110_game_state::spg110_spdmo(machine_config& config)
|
||||
void spg110_game_state::spg110_base_pal(machine_config &config)
|
||||
{
|
||||
spg110_base(config);
|
||||
m_maincpu->set_video_irq_spidman(true);
|
||||
m_screen->set_refresh_hz(50);
|
||||
}
|
||||
|
||||
|
||||
void spg110_easports_game_state::easports_pal(machine_config &config)
|
||||
{
|
||||
spg110_base_pal(config);
|
||||
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void spg110_sstarkar_game_state::machine_start()
|
||||
{
|
||||
// if there's a cart, override the standard mapping
|
||||
@ -603,6 +600,25 @@ ROM_START( jak_spdmoa )
|
||||
ROM_LOAD16_WORD_SWAP( "spiderman.bin", 0x000000, 0x200000, CRC(b2a5a55a) SHA1(93c87ac0387997b753d4f0fb894a0dd02138b460) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( jak_bobb )
|
||||
ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 )
|
||||
ROM_LOAD16_WORD_SWAP( "bob.bin", 0x000000, 0x400000, CRC(16b0b39f) SHA1(43a45e5346d108a9ec1b672fa727e97722b4eaa1) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( easports )
|
||||
ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 )
|
||||
ROM_LOAD16_WORD_SWAP( "ea.u3", 0x000000, 0x400000, CRC(d750089e) SHA1(426f04c3d841103d434a892561db55ade684db54) )
|
||||
ROM_LOAD16_WORD_SWAP( "ea.u4", 0x400000, 0x200000, CRC(20a63445) SHA1(8c3383a353638c7d6b795d15a751275043eacbd0) )
|
||||
|
||||
ROM_REGION( 0x20000, "nvram", ROMREGION_ERASE00 )
|
||||
// There is a coin style battery backing up at least some of the RAM.
|
||||
// The games seems to fail to initialize it properly first time, resulting in a hang shortly after
|
||||
// selecting a game. Provide a default (at least for now)
|
||||
// Random default fills, All 1, or All 0 do not work in this case
|
||||
ROM_LOAD( "nvram", 0x000000, 0x20000, CRC(bfcbd206) SHA1(0f5b730679762547a0658c2cd0d4fa5169b857af) )
|
||||
ROM_END
|
||||
|
||||
|
||||
ROM_START( conyteni )
|
||||
ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASE00 )
|
||||
ROM_LOAD16_WORD_SWAP( "tennis_m29w160eb.bin", 0x000000, 0x200000, CRC(70050f17) SHA1(929f0d8599b7380b5994684424bb91063c4f6569) )
|
||||
@ -635,8 +651,11 @@ ROM_END
|
||||
// JAKKS Pacific Inc TV games
|
||||
CONS( 2004, jak_capb, 0, 0, spg110_base, jak_capb, spg110_game_state, empty_init, "JAKKS Pacific Inc / HotGen Ltd", "Classic Arcade Pinball (JAKKS Pacific TV Game)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
|
||||
|
||||
CONS( 2004, jak_spdmo, jak_spdm, 0, spg110_spdmo, jak_spdmo, spg110_game_state, empty_init, "JAKKS Pacific Inc / Digital Eclipse", "Spider-Man (JAKKS Pacific TV Game) (older hardware, set 1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // this is the smaller more 'square' style joystick that was originally released before the GameKey slot was added.
|
||||
CONS( 2004, jak_spdmoa,jak_spdm, 0, spg110_spdmo, jak_spdmo, spg110_game_state, empty_init, "JAKKS Pacific Inc / Digital Eclipse", "Spider-Man (JAKKS Pacific TV Game) (older hardware, set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // this is the resdesigned stick, but before the GameKey release
|
||||
CONS( 2004, jak_spdmo, jak_spdm, 0, spg110_base, jak_spdmo, spg110_game_state, empty_init, "JAKKS Pacific Inc / Digital Eclipse", "Spider-Man (JAKKS Pacific TV Game) (older hardware, set 1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // this is the smaller more 'square' style joystick that was originally released before the GameKey slot was added.
|
||||
CONS( 2004, jak_spdmoa,jak_spdm, 0, spg110_base, jak_spdmo, spg110_game_state, empty_init, "JAKKS Pacific Inc / Digital Eclipse", "Spider-Man (JAKKS Pacific TV Game) (older hardware, set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // this is the resdesigned stick, but before the GameKey release
|
||||
|
||||
// has Game-Key strings in test mode even if there were no SPG110 Game-Key units at all
|
||||
CONS( 2006, jak_bobb, 0, 0, spg110_base, jak_bobb, spg110_game_state, empty_init, "JAKKS Pacific Inc / HotGen Ltd", "Bob the Builder - Project: Build It (JAKKS Pacific TV Game) (JUN 2 2006 14:42:01)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
|
||||
|
||||
// this was sold by SDW Games for the US market, ROM not yet verified to be the same, also appears in some multigames?
|
||||
CONS( 2003, conyteni, 0, 0, spg110_base, conyteni, spg110_game_state, empty_init, "Conny", "TV Virtual Tennis", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // needs motion inputs, and video fixes, setting to PAL
|
||||
@ -650,3 +669,6 @@ CONS( 200?, conyfght, 0, 0, spg110_base, conyteni, spg110_game_state, e
|
||||
|
||||
// The unit contains no BIOS ROM, was sold by Taikee as Singing Star Karaoke, but also by Imaginarium / ItsMagical in Spain as Karao Kids. Cartridges are compatible.
|
||||
CONS( 200?, sstarkar, 0, 0, sstarkar, conyteni, spg110_sstarkar_game_state, empty_init, "Taikee", "Singing Star Karaoke (World) / Karao Kids (Spain)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // "ItsMagical" brand from Imaginarium
|
||||
|
||||
CONS( 2004, easports, 0, 0, easports_pal, easports, spg110_easports_game_state, empty_init, "JAKKS Pacific Inc / Digital Eclipse", "EA Sports Classics: NHL 95 & FIFA Soccer 96 (JAKKS Pacific TV Game)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
|
||||
// US release has Madden instead of FIFA
|
||||
|
Loading…
Reference in New Issue
Block a user