mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
Fix several issues in DC-based HW (#9150)
- Streamlined logging across chips to use logmacro.h, removed popmessages and printfs in production code; - Add missing include guards in header files; - split Atomiswave into own file from naomi.cpp (dc_atomiswave.cpp); - powervr2.cpp: YUV pitch follows U size, fixes #8999 - powervr2.cpp: move Elan related stuff back into naomi2_state; - naomi.cpp: support for player 2 keyboard inputs; - naomi.cpp: add proper inputs to alpilot/alpilotj and sstrkfgt; - naomi.cpp: hookup lightgun for deathcox; - naomi.cpp: make G2-DMA timings slightly more accurate (fixes sfz3ugd silent BGMs regression caused by implicit insta-DMAs) - dc_g2if.cpp: wrote a device for G2 DMA interface, fixes #9000 ; - dc_g2if.cpp: add E1/E2/DD channels thru template, add area protection, add illegal address and overflow exceptions (fixes loopchk g2 bus tests 0302 and 0303) - aica.cpp: $2814 CA reads doesn't need shifting, fixes ADX repeating sample/hang bugs in many entries [Angelo Salese, MetalliC]; - powervr2.cpp: make ISP/TSP irq to be slower, fixes regression bug with Capcom fighters having frame hiccups [David Haywood, Angelo Salese] - dc_atomiswave.cpp: converted aw_modem_r/_w to 32-bit, added 3p/4p inputs to ggisuka, expose EXID to an input/output ioports for future extensions; - dc_atomiswave.cpp: extend xtrmhnt2 ALL.Net hack for -drc, move around state machine to derive ALL.Net external device mapping instead of driver_init fn, demote to MUP for obvious reasons; - dc_atomiswave: add Area 1 mirrors, fix maxspeed title screen animation; - [MT#8143](https://mametesters.org/view.php?id=8143) is fixed New NOT_WORKING software list additions --------------------------------------- dc.xml: DC Checker for Repair v2.05R (World), Loop Checker v1.00 (World), GD Drive Repair Program v0.1 (World) [Hidden Palace]
This commit is contained in:
parent
7439e33919
commit
5342d0e7f5
114
hash/dc.xml
114
hash/dc.xml
@ -6546,21 +6546,6 @@ P830-****-** : Appears to be a Sega part number for promo discs.
|
||||
</software>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<software name="chkrepair205r" cloneof="chkrepair216r">
|
||||
<description>DC Checker for Repair v2.05R (World)</description>
|
||||
<year>1999</year>
|
||||
<publisher>Sega</publisher>
|
||||
<info name="serial" value="DCSC205R"/>
|
||||
<info name="release" value="19991026"/>
|
||||
<part interface="cdrom" name="cdrom">
|
||||
<diskarea name="cdrom">
|
||||
<disk name="dc checker for repair v2.05r (world)" status="nodump"/>
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<software name="chkrepair216r">
|
||||
<description>DC Checker for Repair v2.16R (World)</description>
|
||||
@ -14051,20 +14036,6 @@ P830-****-** : Appears to be a Sega part number for promo discs.
|
||||
</software>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<software name="chkgd">
|
||||
<description>GD Drive Repair Program v0.1 (World)</description>
|
||||
<year>1998</year>
|
||||
<publisher>Sega</publisher>
|
||||
<info name="serial" value="DCFD01"/>
|
||||
<part interface="cdrom" name="cdrom">
|
||||
<diskarea name="cdrom">
|
||||
<disk name="gd drive repair program v0.1 (world)" status="nodump"/>
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<rom name="Geist.Force-Resorted.cdi" size="812094891" md5="30fe0122b93a3c9d03711c5f74d759a9" sha1="91b221e916f389118190e141547d92a8df476985"/>
|
||||
|
||||
@ -19136,21 +19107,6 @@ P830-****-** : Appears to be a Sega part number for promo discs.
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<!--
|
||||
<software name="loopchk">
|
||||
<description>Loop Checker v1.00 (World)</description>
|
||||
<year>2000</year>
|
||||
<publisher>Sega</publisher>
|
||||
<info name="serial" value="SDPS-1"/>
|
||||
<info name="release" value="20000601"/>
|
||||
<part interface="cdrom" name="cdrom">
|
||||
<diskarea name="cdrom">
|
||||
<disk name="loop checker v1.00 (world)" status="nodump"/>
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
-->
|
||||
|
||||
<software name="lhsmile"> <!-- Sega Rating: Suitable for All Ages -->
|
||||
<!-- http://redump.org/disc/28866/
|
||||
<rom name="Love Hina - Smile Again (Japan).gdi" size="201" crc="57c73c75" md5="0dfa3dc31d20888bd5885d24ede696f0" sha1="3e266d6c2932f64eb8c20a91de03c154b7a25cb8"/>
|
||||
@ -23447,4 +23403,74 @@ P830-****-** : Appears to be a Sega part number for promo discs.
|
||||
</part>
|
||||
</software>
|
||||
-->
|
||||
|
||||
<!-- TODO: N-Z goes here -->
|
||||
|
||||
<!-- Check-GD -->
|
||||
<!--
|
||||
Testers may be run in different modes if hold controller buttons while booting (A+B, Right+X, Left+X, Down+A+B+X, Down+X, Up+X and few others).
|
||||
|
||||
Eventually requires emulated Maple DMA "swap endian" mode (SB_MMSEL register = 0).
|
||||
-->
|
||||
|
||||
<!-- <software name="chkrepair205r" cloneof="chkrepair216r"> -->
|
||||
<software name="chkrepair205r" supported="no">
|
||||
<description>DC Checker for Repair v2.05R (World)</description>
|
||||
<year>1999</year>
|
||||
<publisher>Sega</publisher>
|
||||
<notes><![CDATA[
|
||||
Check-GD program
|
||||
Hangs with a black screen, needs [SH4] SCIF emulation, bypass with NOPs at PC=0xc018f42 and PC=0xc018f54
|
||||
Fails at MMU checks 2-3-4, tries everything back again, stalls on MMU Check_1 back again PC=0x800000a2.
|
||||
]]></notes>
|
||||
<!--<info name="serial" value="DCSC205R"/>-->
|
||||
<info name="serial" value="SPDS-5"/>
|
||||
<info name="release" value="19991027"/>
|
||||
<part interface="cdrom" name="cdrom">
|
||||
<diskarea name="cdrom">
|
||||
<disk name="dc checker for repair v2.05r (world)" sha1="2acfd570b14795da6339eda36a1e3dd0f8dce102"/>
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<software name="loopchk" supported="no">
|
||||
<!-- build number: "V0.800" -->
|
||||
<description>Loop Checker v1.00 (World)</description>
|
||||
<year>1999</year>
|
||||
<publisher>Sega</publisher>
|
||||
<notes><![CDATA[
|
||||
Check-GD program
|
||||
Hangs with a cyan screen, needs [SH4] SCIF emulation, bypass with NOPs at PC=0xc0196da and PC=0xc0196ec
|
||||
Require emulated Maple DMA "swap endian" mode (SB_MMSEL register = 0)
|
||||
cfr. https://github.com/mamedev/mame/issues/9106 for more info.
|
||||
]]></notes>
|
||||
<info name="serial" value="SDPS-1"/>
|
||||
<info name="release" value="19991109"/>
|
||||
<!-- TODO: understand what the various button combinations actually does -->
|
||||
<info name="usage" value="1. Select tests with A button in port A, selected to be run tests will have a dot at string tail; 2. Once done, in main menu press B to select number of times said tests needs to be run cyclically; 3. Press B to undo, A to move on. Select Con't or Halt mode with A; 4. Selected tests will (hopefully) run;"/>
|
||||
<part interface="cdrom" name="cdrom">
|
||||
<diskarea name="cdrom">
|
||||
<disk name="loop checker Ver 1.00 (world)" sha1="cd63dc2bdad2c6ce20af052871bcc77276808910"/>
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<software name="chkgd" supported="no">
|
||||
<!-- build number: V0.720 -->
|
||||
<description>GD Drive Repair Program v0.1 (World)</description>
|
||||
<year>1998</year>
|
||||
<publisher>Sega</publisher>
|
||||
<notes><![CDATA[
|
||||
Check-GD program
|
||||
Stuck with a Sega copyright printed on screen
|
||||
]]></notes>
|
||||
<!--<info name="serial" value="DCFD01"/>-->
|
||||
<info name="serial" value="HKT-999999"/>
|
||||
<info name="release" value="19981201"/>
|
||||
<part interface="cdrom" name="cdrom">
|
||||
<diskarea name="cdrom">
|
||||
<disk name="gd drive repair program ver 0.1 (world)" sha1="4b302df1d4bdffcbad2f2475687000352bb08311"/>
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
</softwarelist>
|
||||
|
@ -3510,8 +3510,10 @@ files {
|
||||
MAME_DIR .. "src/mame/machine/model3.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/monacogp.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/naomi.cpp",
|
||||
MAME_DIR .. "src/mame/includes/naomi.h",
|
||||
MAME_DIR .. "src/mame/drivers/dc_atomiswave.cpp",
|
||||
MAME_DIR .. "src/mame/includes/dc.h",
|
||||
MAME_DIR .. "src/mame/includes/naomi.h",
|
||||
MAME_DIR .. "src/mame/includes/dc_atomiswave.h",
|
||||
MAME_DIR .. "src/mame/drivers/segasp.cpp",
|
||||
MAME_DIR .. "src/mame/includes/segasp.h",
|
||||
MAME_DIR .. "src/mame/machine/dc.cpp",
|
||||
@ -3520,9 +3522,10 @@ files {
|
||||
MAME_DIR .. "src/mame/video/powervr2.h",
|
||||
MAME_DIR .. "src/mame/machine/gunsense.cpp",
|
||||
MAME_DIR .. "src/mame/machine/gunsense.h",
|
||||
MAME_DIR .. "src/mame/machine/naomi.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomig1.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomig1.h",
|
||||
MAME_DIR .. "src/mame/machine/dc_g2if.cpp",
|
||||
MAME_DIR .. "src/mame/machine/dc_g2if.h",
|
||||
MAME_DIR .. "src/mame/machine/naomibd.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomibd.h",
|
||||
MAME_DIR .. "src/mame/machine/naomirom.cpp",
|
||||
|
@ -1578,11 +1578,12 @@ files {
|
||||
MAME_DIR .. "src/mame/machine/mapledev.h",
|
||||
MAME_DIR .. "src/mame/machine/mie.cpp",
|
||||
MAME_DIR .. "src/mame/machine/mie.h",
|
||||
MAME_DIR .. "src/mame/machine/naomi.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomibd.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomibd.h",
|
||||
MAME_DIR .. "src/mame/machine/naomig1.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomig1.h",
|
||||
MAME_DIR .. "src/mame/machine/dc_g2if.cpp",
|
||||
MAME_DIR .. "src/mame/machine/dc_g2if.h",
|
||||
MAME_DIR .. "src/mame/machine/naomigd.cpp",
|
||||
MAME_DIR .. "src/mame/machine/naomigd.h",
|
||||
MAME_DIR .. "src/mame/machine/naomim1.cpp",
|
||||
|
@ -51,7 +51,8 @@ void atapi_hle_device::process_buffer()
|
||||
|
||||
if (m_feature & ATAPI_FEATURES_FLAG_OVL)
|
||||
{
|
||||
printf( "ATAPI_FEATURES_FLAG_OVL not supported\n" );
|
||||
// TODO: DC GD-ROM
|
||||
logerror( "ATAPI_FEATURES_FLAG_OVL not supported\n" );
|
||||
}
|
||||
|
||||
switch (m_phase)
|
||||
|
@ -788,8 +788,8 @@ inline void sh34_base_device::PREFM(const uint16_t opcode)
|
||||
if (m_sh4_mmu_enabled)
|
||||
{
|
||||
addr = addr & 0xFFFFFFE0;
|
||||
dest = sh4_getsqremap(addr); // good enough for naomi-gd rom, probably not much else
|
||||
|
||||
// good enough for NAOMI GD-ROM, not much else
|
||||
dest = sh4_getsqremap(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1615,7 +1615,7 @@ void sh34_base_device::device_reset()
|
||||
m_irln = 15;
|
||||
m_sh2_state->sleep_mode = 0;
|
||||
|
||||
m_sh4_mmu_enabled = 0;
|
||||
m_sh4_mmu_enabled = false;
|
||||
m_cache_dirty = true;
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ protected:
|
||||
int m_md[9];
|
||||
int m_clock;
|
||||
|
||||
// hack 1 = Naomi hack, hack 2 = Work in Progress implementation
|
||||
// hack 1 = Naomi hack, hack 2 = WIP implementation
|
||||
int m_mmuhack;
|
||||
|
||||
uint32_t m_exception_priority[128];
|
||||
@ -377,8 +377,7 @@ protected:
|
||||
|
||||
//void (*m_ftcsr_read_callback)(uint32_t data);
|
||||
|
||||
/* This MMU simulation is good for the simple remap used on Naomi GD-ROM SQ access *ONLY* */
|
||||
uint8_t m_sh4_mmu_enabled;
|
||||
bool m_sh4_mmu_enabled;
|
||||
|
||||
// sh3 internal
|
||||
uint32_t m_sh3internal_upper[0x3000/4];
|
||||
|
@ -731,44 +731,46 @@ void sh4_base_device::sh4_internal_w(offs_t offset, uint32_t data, uint32_t mem_
|
||||
logerror("TEA set to %08x\n", data);
|
||||
break;
|
||||
|
||||
/*
|
||||
LLLL LL-- BBBB BB-- CCCC CCQV ---- -T-A
|
||||
|
||||
L = LRUI = Least recently used ITLB
|
||||
B = URB = UTLB replace boundary
|
||||
C = URC = UTLB replace counter
|
||||
Q = SQMD = Store Queue Mode Bit
|
||||
V = SV = Single Virtual Mode Bit
|
||||
T = TI = TLB invalidate
|
||||
A = AT = Address translation bit (enable)
|
||||
*/
|
||||
case MMUCR: // MMU Control
|
||||
logerror("%s: MMUCR %08x\n", machine().describe_context(), data);
|
||||
m_m[MMUCR] &= 0xffffffff;
|
||||
/*
|
||||
LLLL LL-- BBBB BB-- CCCC CCQV ---- -T-A
|
||||
// MMUCR_AT
|
||||
m_sh4_mmu_enabled = bool(BIT(data, 0));
|
||||
logerror("%s: MMUCR %08x (enable: %d)\n", machine().describe_context(), data, m_sh4_mmu_enabled);
|
||||
|
||||
L = LRUI = Least recently used ITLB
|
||||
B = URB = UTLB replace boundary
|
||||
C = URC = UTLB replace counter
|
||||
Q = SQMD = Store Queue Mode Bit
|
||||
V = SV = Single Virtual Mode Bit
|
||||
T = TI = TLB invaldiate
|
||||
A = AT = Address translation bit (enable)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
if (data & MMUCR_AT)
|
||||
if (m_sh4_mmu_enabled)
|
||||
{
|
||||
m_sh4_mmu_enabled = 1;
|
||||
|
||||
|
||||
// Newer versions of the Dreamcast Katana SDK use MMU to remap the SQ write-back space (cfr. ikaruga and several later NAOMI GD-ROM releases)
|
||||
// Anything beyond that is bound to fail,
|
||||
// i.e. DC WinCE games, DC Linux distros, v2 Sega checkers, aristmk6.cpp
|
||||
#if 0
|
||||
if (m_mmuhack == 1)
|
||||
{
|
||||
printf("SH4 MMU Enabled\n");
|
||||
printf("If you're seeing this, but running something other than a Naomi GD-ROM game then chances are it won't work\n");
|
||||
printf("The MMU emulation is a hack specific to that system\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (m_mmuhack == 2)
|
||||
{
|
||||
for (int i = 0;i < 64;i++)
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (m_utlb[i].V)
|
||||
{
|
||||
printf("(entry %02x | ASID: %02x VPN: %08x V: %02x PPN: %08x SZ: %02x SH: %02x C: %02x PPR: %02x D: %02x WT %02x: SA: %02x TC: %02x)\n",
|
||||
// FIXME: potentially verbose, move to logmacro.h pattern
|
||||
// cfr. MMU Check_4 in v2.xx DC CHECKER
|
||||
logerror("(entry %02x | ASID: %02x VPN: %08x V: %02x PPN: %08x SZ: %02x SH: %02x C: %02x PPR: %02x D: %02x WT %02x: SA: %02x TC: %02x)\n",
|
||||
i,
|
||||
m_utlb[i].ASID,
|
||||
m_utlb[i].VPN << 10,
|
||||
@ -785,12 +787,6 @@ void sh4_base_device::sh4_internal_w(offs_t offset, uint32_t data, uint32_t mem_
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sh4_mmu_enabled = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -17,6 +17,11 @@
|
||||
- Convert I/O registers to space addresses;
|
||||
- Timebases are based on 44100KHz case?
|
||||
- Derive from SCSP device;
|
||||
- Sound clips a bit too much (cfr. deathcox, bdrdown, samba title screen, cfield).
|
||||
According to skmp note: "The [ADX] sound decompression code on the sh4 uses FTRC
|
||||
(float -> int) to convert the samples. Make sure you saturate the value when converting"
|
||||
-> Verify this statement.
|
||||
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
@ -839,19 +844,10 @@ void aica_device::UpdateRegR(int reg)
|
||||
//m_stream->update();
|
||||
int slotnum = MSLC();
|
||||
AICA_SLOT *slot = m_Slots + slotnum;
|
||||
u32 CA;
|
||||
|
||||
if (PCMS(slot) == 0) // 16-bit samples
|
||||
{
|
||||
CA = (slot->cur_addr >> (SHIFT - 1)) & ~1;
|
||||
}
|
||||
else // 8-bit PCM and 4-bit ADPCM
|
||||
{
|
||||
CA = (slot->cur_addr >> SHIFT);
|
||||
}
|
||||
|
||||
//printf("%08x %08x\n",CA,slot->cur_addr & ~1);
|
||||
|
||||
// NB: despite previous implementation this does not depend on PCMS setting.
|
||||
// Was "CA = (slot->cur_addr >> (SHIFT - 1)) & ~1;" on 16-bit path,
|
||||
// causing repeated samples/hangs in several ADX driven entries.
|
||||
u32 CA = (slot->cur_addr >> SHIFT);
|
||||
m_udata.data[0x14 / 2] = CA;
|
||||
}
|
||||
break;
|
||||
@ -918,7 +914,12 @@ void aica_device::w16(u32 addr,u16 val)
|
||||
else if (addr < 0x3300)
|
||||
*((u16 *)(m_DSP.MADRS+(addr - 0x3200) / 2)) = val;
|
||||
else if (addr < 0x3400)
|
||||
popmessage("AICADSP write to undocumented reg %04x -> %04x", addr, val);
|
||||
{
|
||||
// 3300-fc zapped along with the full 0x3000-0x3bfc range,
|
||||
// most likely done by the SDK for convenience in resetting DSP in one go.
|
||||
if (val)
|
||||
logerror("%s: AICADSP write to undocumented reg %04x -> %04x\n", machine().describe_context(), addr, val);
|
||||
}
|
||||
else if (addr < 0x3c00)
|
||||
{
|
||||
*((u16 *)(m_DSP.MPRO+(addr - 0x3400) / 2)) = val;
|
||||
@ -978,7 +979,9 @@ u16 aica_device::r16(u32 addr)
|
||||
v = m_EFSPAN[addr & 0x7f];
|
||||
}
|
||||
else if (addr < 0x2800)
|
||||
popmessage("AICA read undocumented reg %04x", addr);
|
||||
{
|
||||
//logerror("%s: AICA read to undocumented reg %04x\n", machine().describe_context(), addr);
|
||||
}
|
||||
else if (addr < 0x28be)
|
||||
{
|
||||
UpdateRegR(addr & 0xff);
|
||||
@ -1001,11 +1004,15 @@ u16 aica_device::r16(u32 addr)
|
||||
else if (addr < 0x3300)
|
||||
v= *((u16 *)(m_DSP.MADRS+(addr - 0x3200) / 2));
|
||||
else if (addr < 0x3400)
|
||||
popmessage("AICADSP read undocumented reg %04x", addr);
|
||||
{
|
||||
//logerror("%s: AICADSP read to undocumented reg %04x\n", machine().describe_context(), addr);
|
||||
}
|
||||
else if (addr < 0x3c00)
|
||||
v= *((u16 *)(m_DSP.MPRO+(addr - 0x3400) / 2));
|
||||
else if (addr < 0x4000)
|
||||
popmessage("AICADSP read undocumented reg %04x",addr);
|
||||
{
|
||||
//logerror("%s: AICADSP read to undocumented reg %04x\n", machine().describe_context(), addr);
|
||||
}
|
||||
else if (addr < 0x4400)
|
||||
{
|
||||
if (addr & 4)
|
||||
@ -1191,9 +1198,6 @@ s32 aica_device::UpdateSlot(AICA_SLOT *slot)
|
||||
}
|
||||
break;
|
||||
case 1: //normal loop
|
||||
// TODO: loop mechanism causes hangs in Border Down/Metal Slug 6/Karous etc.
|
||||
// - For mslug6 culprit RAM address is 0x13880 ARM side (a flag that should be zeroed somehow)
|
||||
// - The lpend mechanism more or less works if the ARM CPU is downclocked at about 10%.
|
||||
if (*addr[addr_select] >= chanlea)
|
||||
{
|
||||
slot->lpend = 1;
|
||||
|
@ -308,6 +308,7 @@ dassault.cpp
|
||||
dblcrown.cpp
|
||||
dblewing.cpp
|
||||
dbz.cpp
|
||||
dc_atomiswave.cpp
|
||||
dcheese.cpp
|
||||
dcon.cpp
|
||||
dday.cpp
|
||||
|
1516
src/mame/drivers/dc_atomiswave.cpp
Normal file
1516
src/mame/drivers/dc_atomiswave.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,15 @@
|
||||
|
||||
TODO:
|
||||
- RTC error always pops up at start-up, no flash plus bug with ticks (needs rewrite)
|
||||
- cfr. naomi.cpp header for general DC notes;
|
||||
- https://github.com/flyinghead/flycast/blob/master/docs/Notable%20game%20bugs.md
|
||||
For a comprehensive list of issues to be verified;
|
||||
- Fix Check-GD disk usability, cfr. notes in dc.xml;
|
||||
- G1 i/f for GD-ROM needs to be converted in device class and hunted for unsupported features;
|
||||
- VMU;
|
||||
- Modem;
|
||||
|
||||
Old TODO (to be rechecked and moved in XML notes):
|
||||
- Inputs doesn't work most of the time;
|
||||
- Candy Stripe: fills the log with "ATAPI_FEATURES_FLAG_OVL not supported", black screen
|
||||
- Carrier: Jaleco logo uses YUV, but y size is halved?
|
||||
@ -34,229 +43,6 @@
|
||||
Notes:
|
||||
- 0x1a002 of flash ROM returns the region type (0x30=Japan, 0x31=USA, 0x32=Europe). Amusingly, if the value
|
||||
on a non-jp console is different than these ones, the system shows a black swirl (and nothing boots).
|
||||
- gdi file for DCLP (a Dreamcast tester) doesn't have first two tracks info, they are:
|
||||
1 0 4 2048 FILE0001.DUP 0
|
||||
2 1798 0 2352 FILE0002.DUP 0
|
||||
serial i/o also fails on that, work ram addresses that needs to be patched with 0x0009 (nop) are:
|
||||
0xc0196da
|
||||
0xc0196ec
|
||||
Testers may be run in different modes if hold controller buttons while booting (A+B, Right+X, Left+X, Down+A+B+X, Down+X, Up+X and few others),
|
||||
require emulated Maple DMA "swap endian" mode (SB_MMSEL register = 0).
|
||||
SH4 TEST:
|
||||
UBC test (0101):
|
||||
ok
|
||||
FPU test (0201):
|
||||
NG
|
||||
0xc03fe24 work ram flag check (1=error, 0=ok)
|
||||
Cache test (03xx):
|
||||
Cache Read/Write test (0301)
|
||||
NG
|
||||
Cache RAM mode Check (0305)
|
||||
NG
|
||||
MMU test (04xx):
|
||||
asserts
|
||||
TMU test (0501):
|
||||
*_reg check -> ok
|
||||
TCNT* reload -> NG
|
||||
TCNT* underflow irq -> NG
|
||||
MULT test (0601)
|
||||
ok
|
||||
DIVU test (0701)
|
||||
ok
|
||||
Store Queue test (0801):
|
||||
ok
|
||||
SCIF test (0901)
|
||||
NG
|
||||
Private Instruction test (0a01)
|
||||
NG
|
||||
Critical test (0dxx)
|
||||
Critical (Store Queue) test (0d01):
|
||||
ok
|
||||
Critical (Write back) test (0d02):
|
||||
ok
|
||||
Critical (ADD,CMP/EQ) test (0d03):
|
||||
ok
|
||||
Critical (OC_OIX) test (0d04):
|
||||
NG
|
||||
Critical (MAX current) test (0d05):
|
||||
ok (very slow!)
|
||||
Critical (IC Cross Talk) test (0d06):
|
||||
NG
|
||||
Critical (Cache D-array) test (0d07):
|
||||
NG
|
||||
SH-4 BUG (0exx)
|
||||
SH4_BUG 64bit FMOV
|
||||
ok
|
||||
SH4 BUG FIX (64bitFMOV)
|
||||
ok
|
||||
MEM TEST:
|
||||
AICA (0102)
|
||||
ok
|
||||
Work RAM (0204):
|
||||
ok
|
||||
PV64 area (0303):
|
||||
ok
|
||||
PV32 area (0403):
|
||||
ok
|
||||
CLX TEST:
|
||||
CLX internal RAM (0101):
|
||||
ok
|
||||
<Torus> check (0401):
|
||||
(sets up RGB888 mode 2, assuming it's critically failed)
|
||||
TA TEST:
|
||||
TA_YUVINT (0101):
|
||||
ok -> IST_EOXFER_YUV
|
||||
TA_OENDINT (0102):
|
||||
ok -> IST_EOXFER_OPLST
|
||||
TA_OMENDINT (0103):
|
||||
ok -> IST_EOXFER_OPMV
|
||||
TA_TENDINT (0104):
|
||||
ok -> IST_EOXFER_TRLST
|
||||
TA_TMENDINT (0105):
|
||||
ok -> IST_EOXFER_TRMV
|
||||
TA_PTENDINT (0106):
|
||||
ok -> IST_EOXFER_PTLST
|
||||
TA_ISPINT (0107):
|
||||
NG -> ISP/TSP Parameter Overflow (error)
|
||||
TA_OBJINT (0108):
|
||||
NG -> OBJect list pointer Overflow (error)
|
||||
TA_IPINT (0109):
|
||||
NG -> TA: Illegal parameter (error)
|
||||
YUV Converter (0201):
|
||||
ok
|
||||
DDT i/f TEST:
|
||||
Sort, Normal DMA (1) (0101)
|
||||
hangs (wants Sort DMA irq, of course)
|
||||
Sort, Normal DMA (2)
|
||||
...
|
||||
Through
|
||||
NG, hangs again
|
||||
DC_DEINT (0201)
|
||||
ok
|
||||
DC_SDTEINT (0202)
|
||||
ok
|
||||
DC_SDTERINT (0203)
|
||||
ok (but returns error count ++, think it's a bug in the SW)
|
||||
G2 TEST
|
||||
DMA (0101):
|
||||
G2 EXT AREA DETECT:
|
||||
"!!!! ch00 ERROR DETECT !!!!"
|
||||
Interrupt (0301):
|
||||
G2 EXT AREA DETECT
|
||||
DMA END INT
|
||||
hangs
|
||||
Ext Interrupt (06xx)
|
||||
AICA INT (0601)
|
||||
error detect
|
||||
Modem INT (0602)
|
||||
error detect
|
||||
AICA TEST
|
||||
Sound RAM (01xx)
|
||||
Pattern R/W check (0101)
|
||||
ok
|
||||
Register (02xx)
|
||||
CH Data (0201)
|
||||
ok
|
||||
EXT Input (0202)
|
||||
ok
|
||||
DSP Data (0203)
|
||||
ok
|
||||
S_Clock (03xx)
|
||||
50MSEC (0301)
|
||||
NG -> ~0xa58 in 0x702814, must be > 0x889 and < 0x8b0
|
||||
25MSEC (0302)
|
||||
NG -> ~0x372 in 0x702814, must be > 0x443 and < 0x45a
|
||||
Timer (04xx)
|
||||
Timer A (0401)
|
||||
NG
|
||||
Timer B (0402)
|
||||
NG
|
||||
Timer C (0403)
|
||||
NG
|
||||
DMA (05xx)
|
||||
SRAM -> CH Reg (0501)
|
||||
ok
|
||||
SRAM -> Comm Reg (0502)
|
||||
ok
|
||||
SRAM -> DSP Reg (0503)
|
||||
ok
|
||||
CH Reg -> SRAM (0504)
|
||||
ok
|
||||
Comm Reg -> SRAM (0505)
|
||||
ok
|
||||
DSP Reg -> SRAM (0506)
|
||||
ok
|
||||
Clear SRAM (0507)
|
||||
ok
|
||||
Clear CH Reg (0508)
|
||||
ok
|
||||
Clear Comm Reg (0509)
|
||||
ok
|
||||
Clear DSP Reg (050a)
|
||||
ok
|
||||
Interrupt (06xx)
|
||||
Sampling clock (0601)
|
||||
NG (irq 0x400)
|
||||
Timer A (0602)
|
||||
randomly NG/ok
|
||||
Timer B (0603)
|
||||
ok
|
||||
Timer C (0604)
|
||||
ok
|
||||
DMA End (0605)
|
||||
ok
|
||||
Midi Out (0606)
|
||||
NG
|
||||
Main CPU (0607)
|
||||
ok
|
||||
RTC (07xx)
|
||||
Write Protect (0701)
|
||||
ok
|
||||
RW Comp (0702)
|
||||
ok
|
||||
Clock (0703)
|
||||
NG
|
||||
ARM7 (08xx)
|
||||
Load & Start (0801)
|
||||
NG
|
||||
Timer & Intr (0802)
|
||||
NG
|
||||
DMA (0803)
|
||||
NG
|
||||
Ch-Reg R/W (0804)
|
||||
ok
|
||||
SRAM incr (0805)
|
||||
NG
|
||||
SRAM pattern (0806)
|
||||
ok
|
||||
EG (09xx)
|
||||
LSA-Reg Left (0901)
|
||||
ok/NG
|
||||
LSA-Reg Right (0902)
|
||||
ok/NG
|
||||
LSA-Reg Left & Right (0903)
|
||||
ok/NG
|
||||
MIDI (0axx)
|
||||
OEMP bit (0a01)
|
||||
NG
|
||||
OFLL bit (0a02)
|
||||
NG
|
||||
PVRi/f test
|
||||
DMA (01xx)
|
||||
CPU trig (0101)
|
||||
ok
|
||||
INT trig
|
||||
ok
|
||||
Interrupt (02xx)
|
||||
PVR DMA end Int (0201)
|
||||
ok
|
||||
PVR DMA IA Int (0202)
|
||||
NG
|
||||
PVR DMA end (0203)
|
||||
NG
|
||||
Flash test:
|
||||
(SH-4 jumps to la la land as soon as this is started)
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@ -271,30 +57,14 @@
|
||||
#include "machine/dc-ctrl.h"
|
||||
#include "machine/gdrom.h"
|
||||
|
||||
#include "emupal.h"
|
||||
//#include "emupal.h"
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
#include "softlist.h"
|
||||
|
||||
#define CPU_CLOCK (200000000)
|
||||
|
||||
uint64_t dc_cons_state::dcus_idle_skip_r()
|
||||
{
|
||||
//if (m_maincpu->pc()==0xc0ba52a)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(2500));
|
||||
// device_spinuntil_int(m_maincpu);
|
||||
|
||||
return dc_ram[0x2303b0/8];
|
||||
}
|
||||
|
||||
uint64_t dc_cons_state::dcjp_idle_skip_r()
|
||||
{
|
||||
//if (m_maincpu->pc()==0xc0bac62)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(2500));
|
||||
// device_spinuntil_int(m_maincpu);
|
||||
|
||||
return dc_ram[0x2302f8/8];
|
||||
}
|
||||
// cfr. sh4.cpp m_mmuhack
|
||||
#define DC_MMU_HACK_MODE (1)
|
||||
|
||||
void dc_cons_state::init_dc()
|
||||
{
|
||||
@ -304,20 +74,6 @@ void dc_cons_state::init_dc()
|
||||
dreamcast_atapi_init();
|
||||
}
|
||||
|
||||
void dc_cons_state::init_dcus()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2303b0, 0xc2303b7, read64smo_delegate(*this, FUNC(dc_cons_state::dcus_idle_skip_r)));
|
||||
|
||||
init_dc();
|
||||
}
|
||||
|
||||
void dc_cons_state::init_dcjp()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2302f8, 0xc2302ff, read64smo_delegate(*this, FUNC(dc_cons_state::dcjp_idle_skip_r)));
|
||||
|
||||
init_dc();
|
||||
}
|
||||
|
||||
void dc_cons_state::init_tream()
|
||||
{
|
||||
// Modchip connected to BIOS ROM chip changes 4 bytes (actually bits) as shown below, which allow to boot any region games.
|
||||
@ -327,7 +83,7 @@ void dc_cons_state::init_tream()
|
||||
rom[0x523] |= 0x40;
|
||||
rom[0x531] |= 0x40;
|
||||
|
||||
init_dcus();
|
||||
init_dc();
|
||||
}
|
||||
|
||||
uint64_t dc_cons_state::dc_pdtra_r()
|
||||
@ -351,10 +107,12 @@ uint64_t dc_cons_state::dc_pdtra_r()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
cable setting, (0) VGA, (2) TV RGB (3) TV VBS/Y + S/C.
|
||||
Note: several games doesn't like VGA setting (i.e. Idol Janshi wo Tsukucchaou, Airforce Delta), default to composite.
|
||||
*/
|
||||
|
||||
// cable setting, (0) VGA, (2) TV RGB (3) TV VBS/Y + S/C.
|
||||
// Note: several games doesn't like VGA setting,
|
||||
// default to composite for max possible compatibility
|
||||
// (i.e. Idol Janshi wo Tsukucchaou, Airforce Delta)
|
||||
// TODO: identify via script
|
||||
out |= ioport("SCREEN_TYPE")->read() << 8;
|
||||
|
||||
return out;
|
||||
@ -385,16 +143,16 @@ void dc_cons_state::dc_map(address_map &map)
|
||||
map(0x005f7000, 0x005f701f).rw(m_ata, FUNC(ata_interface_device::cs1_r), FUNC(ata_interface_device::cs1_w)).umask64(0x0000ffff0000ffff);
|
||||
map(0x005f7080, 0x005f709f).rw(m_ata, FUNC(ata_interface_device::cs0_r), FUNC(ata_interface_device::cs0_w)).umask64(0x0000ffff0000ffff);
|
||||
map(0x005f7400, 0x005f74ff).rw(FUNC(dc_cons_state::dc_mess_g1_ctrl_r), FUNC(dc_cons_state::dc_mess_g1_ctrl_w));
|
||||
map(0x005f7800, 0x005f78ff).rw(FUNC(dc_cons_state::dc_g2_ctrl_r), FUNC(dc_cons_state::dc_g2_ctrl_w));
|
||||
map(0x005f7800, 0x005f78ff).m(m_g2if, FUNC(dc_g2if_device::amap));
|
||||
map(0x005f7c00, 0x005f7cff).m(m_powervr2, FUNC(powervr2_device::pd_dma_map));
|
||||
map(0x005f8000, 0x005f9fff).m(m_powervr2, FUNC(powervr2_device::ta_map));
|
||||
map(0x00600000, 0x006007ff).rw(FUNC(dc_cons_state::dc_modem_r), FUNC(dc_cons_state::dc_modem_w));
|
||||
map(0x00700000, 0x00707fff).rw(FUNC(dc_cons_state::dc_aica_reg_r), FUNC(dc_cons_state::dc_aica_reg_w));
|
||||
map(0x00710000, 0x0071000f).mirror(0x02000000).rw("aicartc", FUNC(aicartc_device::read), FUNC(aicartc_device::write)).umask64(0x0000ffff0000ffff);
|
||||
map(0x00800000, 0x009fffff).rw(FUNC(dc_cons_state::soundram_r), FUNC(dc_cons_state::soundram_w));
|
||||
map(0x00800000, 0x009fffff).mirror(0x02000000).rw(FUNC(dc_cons_state::soundram_r), FUNC(dc_cons_state::soundram_w));
|
||||
// map(0x01000000, 0x01ffffff) G2 Ext Device #1
|
||||
// map(0x02700000, 0x02707fff) AICA reg mirror
|
||||
// map(0x02800000, 0x02ffffff) AICA wave mem mirror
|
||||
// map(0x02800000, 0x02ffffff) AICA wave mem mirror (loopchk g2 bus DMA test)
|
||||
|
||||
// map(0x03000000, 0x03ffffff) G2 Ext Device #2
|
||||
|
||||
@ -422,6 +180,8 @@ void dc_cons_state::dc_map(address_map &map)
|
||||
map(0x8c000000, 0x8cffffff).ram().share("dc_ram"); // another RAM mirror
|
||||
|
||||
map(0xa0000000, 0xa01fffff).rom().region("maincpu", 0);
|
||||
|
||||
map(0xf4000000, 0xf4003fff).noprw(); // SH-4 operand cache address array
|
||||
}
|
||||
|
||||
void dc_cons_state::dc_port(address_map &map)
|
||||
@ -579,11 +339,6 @@ static INPUT_PORTS_START( dc )
|
||||
|
||||
//A4 - A5, second analog stick, unused on DC
|
||||
|
||||
PORT_START("MAMEDEBUG")
|
||||
PORT_CONFNAME( 0x01, 0x00, "Bilinear Filtering" )
|
||||
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
||||
|
||||
PORT_START("SCREEN_TYPE")
|
||||
PORT_CONFNAME( 0x03, 0x03, "Screen Connection Type" )
|
||||
PORT_CONFSETTING( 0x00, "VGA" )
|
||||
@ -602,11 +357,6 @@ static INPUT_PORTS_START( dcfish )
|
||||
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B")
|
||||
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
|
||||
PORT_START("MAMEDEBUG")
|
||||
PORT_CONFNAME( 0x01, 0x00, "Bilinear Filtering" )
|
||||
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
||||
|
||||
PORT_START("SCREEN_TYPE")
|
||||
PORT_CONFNAME( 0x03, 0x03, "Screen Connection Type" )
|
||||
PORT_CONFSETTING( 0x00, "VGA" )
|
||||
@ -637,9 +387,12 @@ void dc_cons_state::dc_base(machine_config &config)
|
||||
m_maincpu->set_sh4_clock(CPU_CLOCK);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &dc_cons_state::dc_map);
|
||||
m_maincpu->set_addrmap(AS_IO, &dc_cons_state::dc_port);
|
||||
m_maincpu->set_mmu_hacktype(DC_MMU_HACK_MODE);
|
||||
|
||||
TIMER(config, "scantimer").configure_scanline(FUNC(dc_state::dc_scanline), "screen", 0, 1);
|
||||
|
||||
system_bus_config(config, "maincpu");
|
||||
|
||||
ARM7(config, m_soundcpu, ((XTAL(33'868'800)*2)/3)/8); // AICA bus clock is 2/3rds * 33.8688. ARM7 gets 1 bus cycle out of each 8.
|
||||
m_soundcpu->set_addrmap(AS_PROGRAM, &dc_cons_state::dc_audio_map);
|
||||
|
||||
@ -652,9 +405,10 @@ void dc_cons_state::dc_base(machine_config &config)
|
||||
|
||||
/* video hardware */
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
|
||||
screen.set_raw(13458568*2, 857, 0, 640, 524, 0, 480); /* TODO: where pclk actually comes? */
|
||||
// TODO: find exact pclk source
|
||||
screen.set_raw(13458568*2, 857, 0, 640, 524, 0, 480);
|
||||
screen.set_screen_update("powervr2", FUNC(powervr2_device::screen_update));
|
||||
PALETTE(config, "palette").set_entries(0x1000);
|
||||
|
||||
POWERVR2(config, m_powervr2, 0);
|
||||
m_powervr2->irq_callback().set(FUNC(dc_state::pvr_irq));
|
||||
|
||||
@ -843,9 +597,9 @@ ROM_START( dcdev )
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
|
||||
CONS( 1999, dc, dcjp, 0, dc, dc, dc_cons_state, init_dcus, "Sega", "Dreamcast (USA, NTSC)", MACHINE_NOT_WORKING )
|
||||
CONS( 1998, dcjp, 0, 0, dc, dc, dc_cons_state, init_dcjp, "Sega", "Dreamcast (Japan, NTSC)", MACHINE_NOT_WORKING )
|
||||
CONS( 1999, dceu, dcjp, 0, dc, dc, dc_cons_state, init_dcus, "Sega", "Dreamcast (Europe, PAL)", MACHINE_NOT_WORKING )
|
||||
CONS( 1999, dc, dcjp, 0, dc, dc, dc_cons_state, init_dc, "Sega", "Dreamcast (USA, NTSC)", MACHINE_NOT_WORKING )
|
||||
CONS( 1998, dcjp, 0, 0, dc, dc, dc_cons_state, init_dc, "Sega", "Dreamcast (Japan, NTSC)", MACHINE_NOT_WORKING )
|
||||
CONS( 1999, dceu, dcjp, 0, dc, dc, dc_cons_state, init_dc, "Sega", "Dreamcast (Europe, PAL)", MACHINE_NOT_WORKING )
|
||||
CONS( 200?, dctream, dcjp, 0, dc, dc, dc_cons_state, init_tream,"<unknown>", "Treamcast", MACHINE_NOT_WORKING )
|
||||
CONS( 1998, dcdev, 0, 0, dc, dc, dc_cons_state, init_dc, "Sega", "HKT-0120 Sega Dreamcast Development Box", MACHINE_NOT_WORKING )
|
||||
|
||||
@ -909,4 +663,4 @@ ROM_START( dcfish )
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT MACHINE INPUT CLASS INIT ROT COMPANY FULLNAME */
|
||||
GAME( 2000, dcfish, 0, dc_fish, dcfish,dc_cons_state, init_dcjp, ROT0, "Sega", "Fish Life Amazon Playful Edition (Japan)", MACHINE_NOT_WORKING )
|
||||
GAME( 2000, dcfish, 0, dc_fish, dcfish,dc_cons_state, init_dc, ROT0, "Sega", "Fish Life Amazon Playful Edition (Japan)", MACHINE_NOT_WORKING )
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -202,7 +202,7 @@ void segasp_state::segasp_map(address_map &map)
|
||||
map(0x005f6c00, 0x005f6cff).mirror(0x02000000).m(m_maple, FUNC(maple_dc_device::amap));
|
||||
map(0x005f7000, 0x005f70ff).mirror(0x02000000).m(m_naomig1, FUNC(naomi_g1_device::submap)).umask64(0x0000ffff0000ffff);
|
||||
map(0x005f7400, 0x005f74ff).mirror(0x02000000).m(m_naomig1, FUNC(naomi_g1_device::amap));
|
||||
map(0x005f7800, 0x005f78ff).mirror(0x02000000).rw(FUNC(segasp_state::dc_g2_ctrl_r), FUNC(segasp_state::dc_g2_ctrl_w));
|
||||
map(0x005f7800, 0x005f78ff).mirror(0x02000000).m(m_g2if, FUNC(dc_g2if_device::amap));
|
||||
map(0x005f7c00, 0x005f7cff).mirror(0x02000000).m(m_powervr2, FUNC(powervr2_device::pd_dma_map));
|
||||
map(0x005f8000, 0x005f9fff).mirror(0x02000000).m(m_powervr2, FUNC(powervr2_device::ta_map));
|
||||
map(0x00600000, 0x006007ff).mirror(0x02000000).rw(FUNC(segasp_state::dc_modem_r), FUNC(segasp_state::dc_modem_w));
|
||||
@ -255,8 +255,6 @@ void segasp_state::onchip_port(address_map &map)
|
||||
|
||||
|
||||
INPUT_PORTS_START( segasp )
|
||||
PORT_INCLUDE( naomi_debug )
|
||||
|
||||
PORT_START("CFG")
|
||||
PORT_DIPNAME( 0x01, 0x01, "ROM Board type" )
|
||||
PORT_DIPSETTING( 0x00, "other" )
|
||||
@ -310,7 +308,6 @@ INPUT_PORTS_START( segasp )
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 )
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
void segasp_state::segasp(machine_config &config)
|
||||
|
@ -1,36 +1,38 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Angelo Salese, Olivier Galibert, David Haywood, Samuele Zannoli, R. Belmont, ElSemi
|
||||
/*
|
||||
|
||||
dc.h - Sega Dreamcast includes
|
||||
|
||||
*/
|
||||
#ifndef MAME_INCLUDES_DC_H
|
||||
#define MAME_INCLUDES_DC_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "video/powervr2.h"
|
||||
#include "cpu/sh/sh4.h"
|
||||
#include "cpu/arm7/arm7core.h"
|
||||
#include "cpu/arm7/arm7.h"
|
||||
#include "machine/naomig1.h"
|
||||
#include "machine/dc_g2if.h"
|
||||
#include "machine/maple-dc.h"
|
||||
#include "machine/timer.h"
|
||||
#include "sound/aica.h"
|
||||
#include "video/powervr2.h"
|
||||
|
||||
class dc_state : public driver_device
|
||||
{
|
||||
public:
|
||||
dc_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag),
|
||||
dc_framebuffer_ram(*this, "frameram"),
|
||||
dc_texture_ram(*this, "dc_texture_ram"),
|
||||
dc_sound_ram(*this, "dc_sound_ram"),
|
||||
dc_ram(*this, "dc_ram"),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_soundcpu(*this, "soundcpu"),
|
||||
m_powervr2(*this, "powervr2"),
|
||||
m_maple(*this, "maple_dc"),
|
||||
m_naomig1(*this, "rom_board"),
|
||||
m_aica(*this, "aica") { }
|
||||
public:
|
||||
dc_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, dc_framebuffer_ram(*this, "frameram")
|
||||
, dc_texture_ram(*this, "dc_texture_ram")
|
||||
, dc_sound_ram(*this, "dc_sound_ram")
|
||||
, dc_ram(*this, "dc_ram")
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_soundcpu(*this, "soundcpu")
|
||||
, m_powervr2(*this, "powervr2")
|
||||
, m_maple(*this, "maple_dc")
|
||||
, m_naomig1(*this, "rom_board")
|
||||
, m_g2if(*this, "sb_g2if")
|
||||
, m_aica(*this, "aica")
|
||||
{ }
|
||||
|
||||
required_shared_ptr<uint64_t> dc_framebuffer_ram; // '32-bit access area'
|
||||
required_shared_ptr<uint64_t> dc_texture_ram; // '64-bit access area'
|
||||
@ -40,30 +42,18 @@ class dc_state : public driver_device
|
||||
|
||||
/* machine related */
|
||||
uint32_t dc_sysctrl_regs[0x200/4];
|
||||
uint32_t g1bus_regs[0x100/4]; // DC-only
|
||||
uint32_t g2bus_regs[0x100/4];
|
||||
uint8_t m_armrst;
|
||||
|
||||
struct {
|
||||
uint32_t g2_addr;
|
||||
uint32_t root_addr;
|
||||
uint32_t size;
|
||||
uint8_t dir;
|
||||
uint8_t flag;
|
||||
uint8_t indirect;
|
||||
uint8_t start;
|
||||
uint8_t sel;
|
||||
} m_g2_dma[4];
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
TIMER_CALLBACK_MEMBER(g2_dma_irq);
|
||||
void g2_dma_end_w(offs_t channel, u8 state);
|
||||
void g2_dma_error_ia_w(offs_t channel, u8 state);
|
||||
void g2_dma_error_ov_w(offs_t channel, u8 state);
|
||||
TIMER_CALLBACK_MEMBER(ch2_dma_irq);
|
||||
uint32_t dc_aica_reg_r(offs_t offset, uint32_t mem_mask = ~0);
|
||||
void dc_aica_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
uint32_t dc_arm_aica_r(offs_t offset);
|
||||
void dc_arm_aica_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
void g2_dma_execute(address_space &space, int channel);
|
||||
inline int decode_reg32_64(uint32_t offset, uint64_t mem_mask, uint64_t *shift);
|
||||
inline int decode_reg3216_64(uint32_t offset, uint64_t mem_mask, uint64_t *shift);
|
||||
int dc_compute_interrupt_level();
|
||||
@ -73,8 +63,6 @@ class dc_state : public driver_device
|
||||
void dc_sysctrl_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
uint64_t dc_gdrom_r(offs_t offset, uint64_t mem_mask = ~0);
|
||||
void dc_gdrom_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
uint64_t dc_g2_ctrl_r(offs_t offset, uint64_t mem_mask = ~0);
|
||||
void dc_g2_ctrl_w(address_space &space, offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
uint64_t dc_modem_r(offs_t offset, uint64_t mem_mask = ~0);
|
||||
void dc_modem_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
void g1_irq(uint8_t data);
|
||||
@ -92,6 +80,7 @@ class dc_state : public driver_device
|
||||
required_device<powervr2_device> m_powervr2;
|
||||
required_device<maple_dc_device> m_maple;
|
||||
optional_device<naomi_g1_device> m_naomig1;
|
||||
required_device<dc_g2if_device> m_g2if;
|
||||
required_device<aica_device> m_aica;
|
||||
|
||||
void generic_dma(uint32_t main_adr, void *dma_ptr, uint32_t length, uint32_t size, bool to_mainram);
|
||||
@ -101,6 +90,9 @@ class dc_state : public driver_device
|
||||
void naomi_aw_base(machine_config &config);
|
||||
void aica_map(address_map &map);
|
||||
void dc_audio_map(address_map &map);
|
||||
|
||||
protected:
|
||||
void system_bus_config(machine_config &config, const char *cpu_tag);
|
||||
};
|
||||
|
||||
/*--------- Ch2-DMA Control Registers ----------*/
|
||||
|
69
src/mame/includes/dc_atomiswave.h
Normal file
69
src/mame/includes/dc_atomiswave.h
Normal file
@ -0,0 +1,69 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders: Samuele Zannoli, R. Belmont, ElSemi, David Haywood, Angelo Salese, Olivier Galibert, MetalliC
|
||||
|
||||
#ifndef MAME_INCLUDES_DC_ATOMISWAVE_H
|
||||
#define MAME_INCLUDES_DC_ATOMISWAVE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/awboard.h"
|
||||
#include "machine/intelfsh.h"
|
||||
#include "machine/dc-ctrl.h"
|
||||
#include "machine/nvram.h"
|
||||
#include "machine/aicartc.h"
|
||||
//#include "machine/m3comm.h"
|
||||
//#include "machine/gunsense.h"
|
||||
//#include "machine/segashiobd.h"
|
||||
//#include "sound/aica.h"
|
||||
#include "dc.h"
|
||||
//#include "naomi.h"
|
||||
|
||||
class atomiswave_state : public dc_state
|
||||
{
|
||||
public:
|
||||
atomiswave_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: dc_state(mconfig, type, tag)
|
||||
, m_awflash(*this, "awflash")
|
||||
, m_exid_in(*this, "EXID_IN")
|
||||
, m_exid_out(*this, "EXID_OUT")
|
||||
{
|
||||
m_aw_ctrl_type = 0xf0;
|
||||
}
|
||||
|
||||
void aw_base(machine_config &config);
|
||||
void aw1c(machine_config &config);
|
||||
void aw2c(machine_config &config);
|
||||
void aw4c(machine_config &config);
|
||||
|
||||
void init_atomiswave();
|
||||
|
||||
protected:
|
||||
virtual void aw_map(address_map &map);
|
||||
void aw_port(address_map &map);
|
||||
|
||||
private:
|
||||
required_device<macronix_29l001mc_device> m_awflash;
|
||||
optional_ioport m_exid_in;
|
||||
optional_ioport m_exid_out;
|
||||
|
||||
uint32_t aw_modem_r(offs_t offset, uint32_t mem_mask = ~0);
|
||||
void aw_modem_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
u8 m_aw_ctrl_type;
|
||||
// inline int decode_reg32_64(uint32_t offset, uint64_t mem_mask, uint64_t *shift);
|
||||
};
|
||||
|
||||
class atomiswave_xtrmhnt2_state : public atomiswave_state
|
||||
{
|
||||
public:
|
||||
atomiswave_xtrmhnt2_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: atomiswave_state(mconfig, type, tag)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
virtual void aw_map(address_map &map) override;
|
||||
private:
|
||||
uint64_t allnet_hack_r(offs_t offset, uint64_t mem_mask = ~0);
|
||||
};
|
||||
|
||||
#endif // MAME_INCLUDES_DC_ATOMISWAVE_H
|
@ -26,13 +26,8 @@ public:
|
||||
required_device<fujitsu_29lv002tc_device> m_dcflash;
|
||||
|
||||
void init_dc();
|
||||
void init_dcus();
|
||||
void init_dcjp();
|
||||
void init_tream();
|
||||
|
||||
uint64_t dcus_idle_skip_r();
|
||||
uint64_t dcjp_idle_skip_r();
|
||||
|
||||
uint64_t dc_pdtra_r();
|
||||
void dc_pdtra_w(uint64_t data);
|
||||
DECLARE_WRITE_LINE_MEMBER(aica_irq);
|
||||
@ -56,6 +51,8 @@ public:
|
||||
void dc_map(address_map &map);
|
||||
void dc_port(address_map &map);
|
||||
private:
|
||||
uint32_t g1bus_regs[0x100/4]; // DC-only
|
||||
|
||||
uint64_t PDTRA, PCTRA;
|
||||
emu_timer *atapi_timer;
|
||||
int atapi_xferlen, atapi_xferbase, atapi_xfercomplete;
|
||||
|
@ -1,15 +1,15 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Angelo Salese, Olivier Galibert, David Haywood, Samuele Zannoli, R. Belmont, ElSemi
|
||||
/*
|
||||
// copyright-holders: Samuele Zannoli, R. Belmont, ElSemi, David Haywood, Angelo Salese, Olivier Galibert, MetalliC
|
||||
|
||||
naomi.h -> NAOMI includes
|
||||
#ifndef MAME_INCLUDES_NAOMI_H
|
||||
#define MAME_INCLUDES_NAOMI_H
|
||||
|
||||
#pragma once
|
||||
|
||||
*/
|
||||
#include "machine/eepromser.h"
|
||||
#include "machine/intelfsh.h"
|
||||
#include "cpu/arm7/arm7.h"
|
||||
#include "cpu/z80/z80.h"
|
||||
#include "machine/x76f100.h"
|
||||
#include "machine/eepromser.h"
|
||||
//#include "machine/intelfsh.h"
|
||||
#include "machine/maple-dc.h"
|
||||
#include "machine/dc-ctrl.h"
|
||||
#include "machine/mie.h"
|
||||
@ -18,36 +18,28 @@ naomi.h -> NAOMI includes
|
||||
#include "machine/naomim1.h"
|
||||
#include "machine/naomim2.h"
|
||||
#include "machine/naomim4.h"
|
||||
#include "machine/awboard.h"
|
||||
#include "machine/nvram.h"
|
||||
#include "cpu/sh/sh4.h"
|
||||
#include "cpu/arm7/arm7core.h"
|
||||
#include "sound/aica.h"
|
||||
#include "machine/aicartc.h"
|
||||
#include "machine/jvsdev.h"
|
||||
#include "machine/jvs13551.h"
|
||||
#include "machine/m3comm.h"
|
||||
#include "machine/gunsense.h"
|
||||
#include "machine/segashiobd.h"
|
||||
#include "sound/aica.h"
|
||||
#include "dc.h"
|
||||
|
||||
enum {
|
||||
JVSBD_DEFAULT = 0,
|
||||
JVSBD_ADSTICK,
|
||||
JVSBD_LIGHTGUN,
|
||||
JVSBD_MAHJONG,
|
||||
JVSBD_KEYBOARD
|
||||
};
|
||||
|
||||
class naomi_state : public dc_state
|
||||
{
|
||||
public:
|
||||
naomi_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: dc_state(mconfig, type, tag),
|
||||
m_eeprom(*this, "main_eeprom"),
|
||||
m_rombase(*this, "maincpu"),
|
||||
m_mp(*this, "KEY%u", 1U)
|
||||
{ }
|
||||
public:
|
||||
naomi_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: dc_state(mconfig, type, tag)
|
||||
, m_eeprom(*this, "main_eeprom")
|
||||
, m_rombase(*this, "maincpu")
|
||||
, m_mp(*this, "KEY%u", 1U)
|
||||
, m_p1_kb(*this, "P1.ROW%u", 0U)
|
||||
, m_p2_kb(*this, "P2.ROW%u", 0U)
|
||||
{ }
|
||||
|
||||
void naomi_base(machine_config &config);
|
||||
void naomim2(machine_config &config);
|
||||
@ -60,19 +52,15 @@ class naomi_state : public dc_state
|
||||
void naomigd_kb(machine_config &config);
|
||||
void naomim4(machine_config &config);
|
||||
|
||||
void init_naomigd();
|
||||
void init_ggxx();
|
||||
void init_ggxxrl();
|
||||
void init_ggxxsla();
|
||||
void init_naomi();
|
||||
void init_naomigd_mp();
|
||||
void init_sfz3ugd();
|
||||
void init_hotd2();
|
||||
void init_naomi_mp();
|
||||
void init_hotd2();
|
||||
void init_naomigd();
|
||||
void init_naomigd_mp();
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER(naomi_mp_r);
|
||||
DECLARE_CUSTOM_INPUT_MEMBER(suchie3_mp_r);
|
||||
DECLARE_CUSTOM_INPUT_MEMBER(naomi_kb_r);
|
||||
template <int P> DECLARE_CUSTOM_INPUT_MEMBER(naomi_kb_r);
|
||||
DECLARE_INPUT_CHANGED_MEMBER(naomi_mp_w);
|
||||
|
||||
uint64_t naomi2_biose_idle_skip_r();
|
||||
@ -81,6 +69,8 @@ protected:
|
||||
required_device<eeprom_serial_93cxx_device> m_eeprom;
|
||||
optional_region_ptr<uint64_t> m_rombase;
|
||||
optional_ioport_array<5> m_mp;
|
||||
optional_ioport_array<5> m_p1_kb;
|
||||
optional_ioport_array<5> m_p2_kb;
|
||||
|
||||
DECLARE_MACHINE_RESET(naomi);
|
||||
DECLARE_WRITE_LINE_MEMBER(external_reset);
|
||||
@ -94,14 +84,6 @@ protected:
|
||||
uint8_t asciihex_to_dec(uint8_t in);
|
||||
void create_pic_from_retdat();
|
||||
|
||||
uint64_t naomi_biose_idle_skip_r();
|
||||
uint64_t naomi_biosh_idle_skip_r();
|
||||
uint64_t naomigd_ggxxsla_idle_skip_r();
|
||||
uint64_t naomigd_ggxx_idle_skip_r();
|
||||
uint64_t naomigd_ggxxrl_idle_skip_r();
|
||||
uint64_t naomigd_sfz3ugd_idle_skip_r();
|
||||
uint64_t hotd2_idle_skip_r();
|
||||
|
||||
void naomi_map(address_map &map);
|
||||
void naomi_port(address_map &map);
|
||||
|
||||
@ -132,40 +114,12 @@ private:
|
||||
required_shared_ptr<uint64_t> m_elan_ram;
|
||||
required_device<powervr2_device> m_powervr2_slave;
|
||||
|
||||
void both_pvr2_ta_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
void naomi2_map(address_map &map);
|
||||
|
||||
void both_pvr2_ta_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
uint32_t elan_regs_r(offs_t offset);
|
||||
void elan_regs_w(offs_t offset, uint32_t data);
|
||||
};
|
||||
|
||||
class atomiswave_state : public dc_state
|
||||
{
|
||||
public:
|
||||
atomiswave_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: dc_state(mconfig, type, tag),
|
||||
m_awflash(*this, "awflash")
|
||||
{ }
|
||||
|
||||
void aw_base(machine_config &config);
|
||||
void aw1c(machine_config &config);
|
||||
void aw2c(machine_config &config);
|
||||
|
||||
void init_atomiswave();
|
||||
void init_xtrmhnt2();
|
||||
|
||||
private:
|
||||
required_device<macronix_29l001mc_device> m_awflash;
|
||||
|
||||
uint64_t aw_flash_r(offs_t offset);
|
||||
void aw_flash_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
uint64_t aw_modem_r(offs_t offset, uint64_t mem_mask = ~0);
|
||||
void aw_modem_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
|
||||
uint64_t xtrmhnt2_hack_r();
|
||||
|
||||
void aw_map(address_map &map);
|
||||
void aw_port(address_map &map);
|
||||
|
||||
uint8_t aw_ctrl_type;
|
||||
inline int decode_reg32_64(uint32_t offset, uint64_t mem_mask, uint64_t *shift);
|
||||
};
|
||||
|
||||
INPUT_PORTS_EXTERN( naomi_debug );
|
||||
#endif // MAME_INCLUDES_NAOMI_H
|
||||
|
@ -6,6 +6,11 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MAME_INCLUDES_SEGASP_H
|
||||
#define MAME_INCLUDES_SEGASP_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "naomi.h"
|
||||
|
||||
class segasp_state : public naomi_state
|
||||
@ -36,3 +41,5 @@ private:
|
||||
void onchip_port(address_map &map);
|
||||
void segasp_map(address_map &map);
|
||||
};
|
||||
|
||||
#endif // MAME_INCLUDES_SEGASP_H
|
||||
|
@ -1,13 +1,15 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Angelo Salese, Olivier Galibert, David Haywood, Samuele Zannoli, R. Belmont, ElSemi
|
||||
// copyright-holders: Samuele Zannoli, R. Belmont, ElSemi, David Haywood, Angelo Salese, Olivier Galibert, MetalliC
|
||||
/*
|
||||
|
||||
dc.c - Sega Dreamcast hardware
|
||||
dc.cpp - Sega Dreamcast hardware
|
||||
|
||||
Misc interfacing to common DC buses over the various clients.
|
||||
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "debugger.h"
|
||||
//#include "debugger.h"
|
||||
#include "includes/dc.h"
|
||||
#include "cpu/sh/sh4.h"
|
||||
#include "cpu/arm7/arm7core.h"
|
||||
@ -87,17 +89,28 @@ void dc_state::generic_dma(uint32_t main_adr, void *dma_ptr, uint32_t length, ui
|
||||
ddt.source = main_adr;
|
||||
ddt.buffer = dma_ptr;
|
||||
ddt.length = length;
|
||||
ddt.size =size;
|
||||
ddt.size = size;
|
||||
ddt.direction = to_mainram;
|
||||
ddt.channel = 0;
|
||||
ddt.mode = -1;
|
||||
m_maincpu->sh4_dma_ddt(&ddt);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dc_state::g2_dma_irq)
|
||||
void dc_state::g2_dma_end_w(offs_t channel, u8 state)
|
||||
{
|
||||
m_g2_dma[param].start = g2bus_regs[SB_ADST + (param * 8)] = 0;
|
||||
dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_AICA << param;
|
||||
dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_AICA << channel;
|
||||
dc_update_interrupt_status();
|
||||
}
|
||||
|
||||
void dc_state::g2_dma_error_ia_w(offs_t channel, u8 state)
|
||||
{
|
||||
dc_sysctrl_regs[SB_ISTERR] |= 0x8000 << channel;
|
||||
dc_update_interrupt_status();
|
||||
}
|
||||
|
||||
void dc_state::g2_dma_error_ov_w(offs_t channel, u8 state)
|
||||
{
|
||||
dc_sysctrl_regs[SB_ISTERR] |= 0x80000 << channel;
|
||||
dc_update_interrupt_status();
|
||||
}
|
||||
|
||||
@ -189,51 +202,12 @@ void dc_state::maple_irq(uint8_t data)
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dc_state::ch2_dma_irq)
|
||||
{
|
||||
dc_sysctrl_regs[SB_C2DLEN]=0;
|
||||
dc_sysctrl_regs[SB_C2DST]=0;
|
||||
dc_sysctrl_regs[SB_C2DLEN] = 0;
|
||||
dc_sysctrl_regs[SB_C2DST] = 0;
|
||||
dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_CH2;
|
||||
dc_update_interrupt_status();
|
||||
}
|
||||
|
||||
void dc_state::g2_dma_execute(address_space &space, int channel)
|
||||
{
|
||||
uint32_t src,dst,size;
|
||||
dst = m_g2_dma[channel].g2_addr;
|
||||
src = m_g2_dma[channel].root_addr;
|
||||
size = 0;
|
||||
|
||||
/* 0 rounding size = 32 Mbytes */
|
||||
if (m_g2_dma[channel].size == 0) { m_g2_dma[channel].size = 0x200000; }
|
||||
|
||||
if (m_g2_dma[channel].dir == 0)
|
||||
{
|
||||
for (; size<m_g2_dma[channel].size; size += 4)
|
||||
{
|
||||
space.write_dword(dst,space.read_dword(src));
|
||||
src+=4;
|
||||
dst+=4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; size<m_g2_dma[channel].size; size += 4)
|
||||
{
|
||||
space.write_dword(src,space.read_dword(dst));
|
||||
src+=4;
|
||||
dst+=4;
|
||||
}
|
||||
}
|
||||
|
||||
/* update the params*/
|
||||
m_g2_dma[channel].g2_addr = g2bus_regs[SB_ADSTAG + (channel * 8)] = dst;
|
||||
m_g2_dma[channel].root_addr = g2bus_regs[SB_ADSTAR + (channel * 8)] = src;
|
||||
m_g2_dma[channel].size = g2bus_regs[SB_ADLEN + (channel * 8)] = 0;
|
||||
m_g2_dma[channel].flag = (m_g2_dma[channel].indirect & 1) ? 1 : 0;
|
||||
/* Note: if you trigger an instant DMA IRQ trigger, sfz3upper doesn't play any bgm. */
|
||||
/* TODO: timing of this */
|
||||
machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(m_g2_dma[channel].size / 4), timer_expired_delegate(FUNC(dc_state::g2_dma_irq), this), channel);
|
||||
}
|
||||
|
||||
// register decode helpers
|
||||
|
||||
// this accepts only 32-bit accesses
|
||||
@ -340,19 +314,10 @@ void dc_state::dc_update_interrupt_status()
|
||||
m_maincpu->sh4_set_irln_input(15-level);
|
||||
|
||||
/* Wave DMA HW trigger */
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (m_g2_dma[i].flag && ((m_g2_dma[i].sel & 2) == 2))
|
||||
{
|
||||
if ((dc_sysctrl_regs[SB_G2DTNRM] & dc_sysctrl_regs[SB_ISTNRM]) || (dc_sysctrl_regs[SB_G2DTEXT] & dc_sysctrl_regs[SB_ISTEXT]))
|
||||
{
|
||||
address_space &space = m_maincpu->space(AS_PROGRAM);
|
||||
|
||||
printf("Wave DMA HW trigger\n");
|
||||
g2_dma_execute(space, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_g2if->hw_irq_trigger_hs(
|
||||
dc_sysctrl_regs[SB_G2DTNRM] & dc_sysctrl_regs[SB_ISTNRM],
|
||||
dc_sysctrl_regs[SB_G2DTEXT] & dc_sysctrl_regs[SB_ISTEXT]
|
||||
);
|
||||
|
||||
/* PVR-DMA HW trigger */
|
||||
if(m_powervr2->m_pvr_dma.flag && ((m_powervr2->m_pvr_dma.sel & 1) == 1))
|
||||
@ -361,12 +326,13 @@ void dc_state::dc_update_interrupt_status()
|
||||
{
|
||||
address_space &space = m_maincpu->space(AS_PROGRAM);
|
||||
|
||||
printf("PVR-DMA HW trigger\n");
|
||||
logerror("PVR-DMA HW trigger\n");
|
||||
m_powervr2->pvr_dma_execute(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: convert SYSCTRL to device I/F (NAOMI2 needs two of these)
|
||||
uint64_t dc_state::dc_sysctrl_r(offs_t offset, uint64_t mem_mask)
|
||||
{
|
||||
int reg;
|
||||
@ -519,74 +485,6 @@ void dc_state::dc_gdrom_w(offs_t offset, uint64_t data, uint64_t mem_mask)
|
||||
osd_printf_verbose("GDROM: [%08x=%x]write %x to %x, mask %x\n", 0x5f7000+off*4, dat, data, offset, mem_mask);
|
||||
}
|
||||
|
||||
uint64_t dc_state::dc_g2_ctrl_r(offs_t offset, uint64_t mem_mask)
|
||||
{
|
||||
int reg;
|
||||
uint64_t shift;
|
||||
|
||||
reg = decode_reg32_64(offset, mem_mask, &shift);
|
||||
osd_printf_verbose("G2CTRL: Unmapped read %08x\n", 0x5f7800+reg*4);
|
||||
return (uint64_t)g2bus_regs[reg] << shift;
|
||||
}
|
||||
|
||||
void dc_state::dc_g2_ctrl_w(address_space &space, offs_t offset, uint64_t data, uint64_t mem_mask)
|
||||
{
|
||||
int reg;
|
||||
uint64_t shift;
|
||||
uint32_t dat;
|
||||
uint8_t old;
|
||||
|
||||
reg = decode_reg32_64(offset, mem_mask, &shift);
|
||||
dat = (uint32_t)(data >> shift);
|
||||
|
||||
g2bus_regs[reg] = dat; // 5f7800+reg*4=dat
|
||||
|
||||
if (reg >= (0x80 / 4))
|
||||
return;
|
||||
int g2chan = reg >> 3;
|
||||
switch (reg & 7)
|
||||
{
|
||||
/*G2 Address register*/
|
||||
case SB_ADSTAG: m_g2_dma[g2chan].g2_addr = dat; break;
|
||||
/*Root address (work ram)*/
|
||||
case SB_ADSTAR: m_g2_dma[g2chan].root_addr = dat; break;
|
||||
/*DMA size (in dword units, bit 31 is "set dma initiation enable setting to 0"*/
|
||||
case SB_ADLEN:
|
||||
m_g2_dma[g2chan].size = dat & 0x7fffffff;
|
||||
m_g2_dma[g2chan].indirect = (dat & 0x80000000) >> 31;
|
||||
break;
|
||||
/*0 = root memory to aica / 1 = aica to root memory*/
|
||||
case SB_ADDIR: m_g2_dma[g2chan].dir = (dat & 1); break;
|
||||
/*dma flag (active HIGH, bug in docs)*/
|
||||
case SB_ADEN: m_g2_dma[g2chan].flag = (dat & 1); break;
|
||||
/*
|
||||
SB_ADTSEL
|
||||
bit 1: (0) Wave DMA through SB_ADST flag (1) Wave DMA through irq trigger, defined by SB_G2DTNRM / SB_G2DTEXT
|
||||
*/
|
||||
case SB_ADTSEL: m_g2_dma[g2chan].sel = dat & 7; break;
|
||||
/*ready for dma'ing*/
|
||||
case SB_ADST:
|
||||
old = m_g2_dma[g2chan].start & 1;
|
||||
m_g2_dma[g2chan].start = dat & 1;
|
||||
|
||||
#if DEBUG_AICA_DMA
|
||||
printf("AICA: G2-DMA start \n");
|
||||
printf("DST %08x SRC %08x SIZE %08x IND %02x\n",m_g2_dma[g2chan].g2_addr,m_g2_dma[g2chan].root_addr,m_g2_dma[g2chan].size,m_g2_dma[g2chan].indirect);
|
||||
printf("SEL %08x ST %08x FLAG %08x DIR %02x\n",m_g2_dma[g2chan].sel,m_g2_dma[g2chan].start,m_g2_dma[g2chan].flag,m_g2_dma[g2chan].dir);
|
||||
#endif
|
||||
|
||||
//osd_printf_verbose("SB_ADST data %08x\n",dat);
|
||||
if (((old & 1) == 0) && m_g2_dma[g2chan].flag && m_g2_dma[g2chan].start && ((m_g2_dma[g2chan].sel & 2) == 0)) // 0 -> 1
|
||||
g2_dma_execute(space, g2chan);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* might access the unhandled DMAs, so tell us if this happens. */
|
||||
//printf("Unhandled G2 register [%08x] -> %08x\n",reg,dat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int dc_state::decode_reg_64(uint32_t offset, uint64_t mem_mask, uint64_t *shift)
|
||||
{
|
||||
int reg = offset * 2;
|
||||
@ -638,16 +536,6 @@ void dc_state::dc_modem_w(offs_t offset, uint64_t data, uint64_t mem_mask)
|
||||
osd_printf_verbose("MODEM: [%08x=%x] write %x to %x, mask %x\n", 0x600000+reg*4, dat, data, offset, mem_mask);
|
||||
}
|
||||
|
||||
#define SAVE_G2DMA(x) \
|
||||
save_item(NAME(m_g2_dma[x].g2_addr)); \
|
||||
save_item(NAME(m_g2_dma[x].root_addr)); \
|
||||
save_item(NAME(m_g2_dma[x].size)); \
|
||||
save_item(NAME(m_g2_dma[x].dir)); \
|
||||
save_item(NAME(m_g2_dma[x].flag)); \
|
||||
save_item(NAME(m_g2_dma[x].indirect)); \
|
||||
save_item(NAME(m_g2_dma[x].start)); \
|
||||
save_item(NAME(m_g2_dma[x].sel));
|
||||
|
||||
void dc_state::machine_start()
|
||||
{
|
||||
// dccons doesn't have a specific g1 device yet
|
||||
@ -655,15 +543,11 @@ void dc_state::machine_start()
|
||||
m_naomig1->set_dma_cb(naomi_g1_device::dma_cb(&dc_state::generic_dma, this));
|
||||
|
||||
m_maincpu->sh2drc_set_options(SH2DRC_STRICT_VERIFY | SH2DRC_STRICT_PCREL);
|
||||
// TODO: repeated in dccons.cpp init_dc (NAOMI also uses double RAM)
|
||||
m_maincpu->sh2drc_add_fastram(0x0c000000, 0x0cffffff, false, dc_ram);
|
||||
|
||||
// save states
|
||||
save_pointer(NAME(dc_sysctrl_regs), 0x200/4);
|
||||
save_pointer(NAME(g2bus_regs), 0x100/4);
|
||||
SAVE_G2DMA(0)
|
||||
SAVE_G2DMA(1)
|
||||
SAVE_G2DMA(2)
|
||||
SAVE_G2DMA(3)
|
||||
}
|
||||
|
||||
void dc_state::machine_reset()
|
||||
@ -768,3 +652,12 @@ TIMER_DEVICE_CALLBACK_MEMBER(dc_state::dc_scanline)
|
||||
{
|
||||
m_powervr2->pvr_scanline_timer(param);
|
||||
}
|
||||
|
||||
void dc_state::system_bus_config(machine_config &config, const char *cpu_tag)
|
||||
{
|
||||
DC_G2IF(config, m_g2if, XTAL(25'000'000));
|
||||
m_g2if->set_host_space(cpu_tag, AS_PROGRAM);
|
||||
m_g2if->int_cb().set(FUNC(dc_state::g2_dma_end_w));
|
||||
m_g2if->error_ia_cb().set(FUNC(dc_state::g2_dma_error_ia_w));
|
||||
m_g2if->error_ov_cb().set(FUNC(dc_state::g2_dma_error_ov_w));
|
||||
}
|
||||
|
538
src/mame/machine/dc_g2if.cpp
Normal file
538
src/mame/machine/dc_g2if.cpp
Normal file
@ -0,0 +1,538 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Angelo Salese
|
||||
/**************************************************************************************************
|
||||
|
||||
Sega Dreamcast G2 System Bus I/F
|
||||
|
||||
TODO:
|
||||
- Single-step instead of transfering in one go;
|
||||
- Abort DMA if suspend mode is triggered;
|
||||
- Time Out mechanism thru DS# & TR# signals;
|
||||
- External pin enable in trigger select;
|
||||
- Create a pure abstract interface shared with PVR-DMA I/F
|
||||
(one channel, different max size, simpler tsel, no suspend,
|
||||
different security code & area protection);
|
||||
- DMA starts should send DDT requests and being notified back to use this i/f implementation
|
||||
anyway. Exact purpose is unknown, maybe it's for granting use of the bus?
|
||||
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "dc_g2if.h"
|
||||
|
||||
#define LOG_WARN (1U << 1)
|
||||
#define LOG_DMA (1U << 2) // log DMA starts with CPU triggers (.tsel bit 1 == 0)
|
||||
#define LOG_HWTRIG (1U << 3) // log DMA starts with HW triggers (.tsel bit 1 == 1)
|
||||
#define LOG_DMAEND (1U << 4) // log DMA event ends
|
||||
#define LOG_ILLEGAL (1U << 5) // log illegal/malformed addresses
|
||||
|
||||
#define VERBOSE (LOG_WARN | LOG_DMA | LOG_HWTRIG | LOG_DMAEND | LOG_ILLEGAL)
|
||||
//#define LOG_OUTPUT_STREAM std::cout
|
||||
#include "logmacro.h"
|
||||
|
||||
#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
|
||||
#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__)
|
||||
#define LOGHWTRIG(...) LOGMASKED(LOG_HWTRIG, __VA_ARGS__)
|
||||
#define LOGDMAEND(...) LOGMASKED(LOG_DMAEND, __VA_ARGS__)
|
||||
#define LOGILLEGAL(...) LOGMASKED(LOG_ILLEGAL, __VA_ARGS__)
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(DC_G2IF, dc_g2if_device, "dc_g2if", "Sega Dreamcast G2 I/F System Bus")
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// dc_g2if_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
|
||||
dc_g2if_device::dc_g2if_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, DC_G2IF, tag, owner, clock)
|
||||
, m_host_space(*this, finder_base::DUMMY_TAG, -1)
|
||||
, m_int_w(*this)
|
||||
, m_error_ia_w(*this)
|
||||
, m_error_ov_w(*this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
|
||||
void dc_g2if_device::device_start()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
m_dma[i].end_timer = timer_alloc(i);
|
||||
}
|
||||
|
||||
m_int_w.resolve();
|
||||
m_error_ia_w.resolve();
|
||||
m_error_ov_w.resolve();
|
||||
|
||||
save_item(STRUCT_MEMBER(m_dma, g2_addr));
|
||||
save_item(STRUCT_MEMBER(m_dma, root_addr));
|
||||
save_item(STRUCT_MEMBER(m_dma, len));
|
||||
save_item(STRUCT_MEMBER(m_dma, size));
|
||||
save_item(STRUCT_MEMBER(m_dma, mode));
|
||||
save_item(STRUCT_MEMBER(m_dma, dir));
|
||||
save_item(STRUCT_MEMBER(m_dma, enable));
|
||||
save_item(STRUCT_MEMBER(m_dma, in_progress));
|
||||
save_item(STRUCT_MEMBER(m_dma, start));
|
||||
save_item(STRUCT_MEMBER(m_dma, tsel));
|
||||
save_item(STRUCT_MEMBER(m_dma, hw_trigger));
|
||||
save_item(NAME(m_g2apro.top_addr));
|
||||
save_item(NAME(m_g2apro.bottom_addr));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
|
||||
void dc_g2if_device::device_reset()
|
||||
{
|
||||
for (int ch = 0; ch < 4; ch ++)
|
||||
{
|
||||
m_dma[ch].g2_addr = 0;
|
||||
m_dma[ch].root_addr = 0;
|
||||
m_dma[ch].len = 0;
|
||||
m_dma[ch].size = 0;
|
||||
m_dma[ch].mode = false;
|
||||
m_dma[ch].dir = false;
|
||||
m_dma[ch].enable = false;
|
||||
m_dma[ch].in_progress = false;
|
||||
m_dma[ch].start = false;
|
||||
m_dma[ch].tsel = 0;
|
||||
m_dma[ch].hw_trigger = false;
|
||||
m_dma[ch].end_timer->adjust(attotime::never);
|
||||
}
|
||||
}
|
||||
|
||||
void dc_g2if_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
u8 channel = (u8)id;
|
||||
bool dma_result = (param == 1);
|
||||
m_dma[channel].in_progress = false;
|
||||
m_dma[channel].start = false;
|
||||
LOGDMAEND("DMA%d %s\n", id, dma_result ? "normal end" : "overflow error");
|
||||
|
||||
if (dma_result)
|
||||
m_int_w(channel, 1);
|
||||
else
|
||||
m_error_ov_w(channel, 1);
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// READ/WRITE HANDLERS
|
||||
//**************************************************************************
|
||||
|
||||
template <u8 Channel> void dc_g2if_device::channel_map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x03).rw(FUNC(dc_g2if_device::stag_r<Channel>), FUNC(dc_g2if_device::stag_w<Channel>));
|
||||
map(0x04, 0x07).rw(FUNC(dc_g2if_device::star_r<Channel>), FUNC(dc_g2if_device::star_w<Channel>));
|
||||
map(0x08, 0x0b).rw(FUNC(dc_g2if_device::len_r<Channel>), FUNC(dc_g2if_device::len_w<Channel>));
|
||||
map(0x0c, 0x0f).rw(FUNC(dc_g2if_device::dir_r<Channel>), FUNC(dc_g2if_device::dir_w<Channel>));
|
||||
map(0x10, 0x13).rw(FUNC(dc_g2if_device::tsel_r<Channel>), FUNC(dc_g2if_device::tsel_w<Channel>));
|
||||
map(0x14, 0x17).rw(FUNC(dc_g2if_device::en_r<Channel>), FUNC(dc_g2if_device::en_w<Channel>));
|
||||
map(0x18, 0x1b).rw(FUNC(dc_g2if_device::st_r<Channel>), FUNC(dc_g2if_device::st_w<Channel>));
|
||||
map(0x1c, 0x1f).rw(FUNC(dc_g2if_device::susp_r<Channel>), FUNC(dc_g2if_device::susp_w<Channel>));
|
||||
}
|
||||
|
||||
// Instantiate channel maps
|
||||
template void dc_g2if_device::channel_map<0>(address_map &map);
|
||||
template void dc_g2if_device::channel_map<1>(address_map &map);
|
||||
template void dc_g2if_device::channel_map<2>(address_map &map);
|
||||
template void dc_g2if_device::channel_map<3>(address_map &map);
|
||||
|
||||
void dc_g2if_device::amap(address_map &map)
|
||||
{
|
||||
// 0x5f7800-ff
|
||||
// SB_AD*
|
||||
map(0x00, 0x1f).m(FUNC(dc_g2if_device::channel_map<0>));
|
||||
// SB_E1*
|
||||
map(0x20, 0x3f).m(FUNC(dc_g2if_device::channel_map<1>));
|
||||
// SB_E2*
|
||||
map(0x40, 0x5f).m(FUNC(dc_g2if_device::channel_map<2>));
|
||||
// SB_DD*
|
||||
map(0x60, 0x7f).m(FUNC(dc_g2if_device::channel_map<3>));
|
||||
|
||||
map(0x80, 0x83).r(FUNC(dc_g2if_device::g2id_r));
|
||||
|
||||
// map(0x90, 0x93).rw SB_G2DSTO #DS timeout
|
||||
// map(0x94, 0x97).rw SB_G2TRTO #TR timeout
|
||||
// map(0x98, 0x9b).rw SB_G2MDMTO modem wait timeout
|
||||
// map(0x9c, 0x9f).rw SB_G2MDMW modem wait time
|
||||
|
||||
map(0xbc, 0xbf).w(FUNC(dc_g2if_device::g2apro_w));
|
||||
|
||||
// map(0xc0, 0xcb).r SB_AD*D live register reads (STAG, STAR, LEN)
|
||||
// map(0xd0, 0xdb).r SB_E1*D live register reads
|
||||
// map(0xe0, 0xeb).r SB_E2*D live register reads
|
||||
// map(0xf0, 0xfb).r SB_DD*D live register reads
|
||||
}
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::stag_r()
|
||||
{
|
||||
return m_dma[Channel].g2_addr;
|
||||
}
|
||||
|
||||
// SB_**STAG
|
||||
// G2 bus start address
|
||||
template <u8 Channel> void dc_g2if_device::stag_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_dma[Channel].g2_addr);
|
||||
|
||||
if (!g2_address_check(m_dma[Channel].g2_addr))
|
||||
{
|
||||
LOGILLEGAL("%s: G2 illegal Address trap %08x (%08x)\n", machine().describe_context(), data, mem_mask);
|
||||
m_error_ia_w(Channel, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::star_r()
|
||||
{
|
||||
return m_dma[Channel].root_addr;
|
||||
}
|
||||
|
||||
// SB_**STAR
|
||||
// root bus (SH4) start address
|
||||
template <u8 Channel> void dc_g2if_device::star_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_dma[Channel].root_addr);
|
||||
|
||||
if (!root_address_check(m_dma[Channel].root_addr))
|
||||
{
|
||||
LOGILLEGAL("%s: root illegal Address trap %08x (%08x)\n", machine().describe_context(), data, mem_mask);
|
||||
m_error_ia_w(Channel, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::len_r()
|
||||
{
|
||||
return m_dma[Channel].len;
|
||||
}
|
||||
|
||||
/*
|
||||
* SB_**LEN
|
||||
* x--- ---- ---- ---- ---- ---- ---- ---- DMA transfer mode
|
||||
* (0) Restart
|
||||
* (1) End (enable register clears to '0')
|
||||
* ---- ---x xxxx xxxx xxxx xxxx xxx- ---- DMA transfer length
|
||||
* (all buses?)
|
||||
*/
|
||||
template <u8 Channel> void dc_g2if_device::len_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_dma[Channel].len);
|
||||
// log an attempt if any of the reserved bits 30-25 and 4-0 are set
|
||||
if (m_dma[Channel].len & 0x7fe0001f)
|
||||
LOGWARN("%s: DMA%d LEN setup %08x (mask=%08x)!\n", machine().describe_context(), data, mem_mask);
|
||||
// m_dma[Channel].size = m_dma[Channel].len & 0x7fffffff;
|
||||
m_dma[Channel].size = m_dma[Channel].len & 0x001fffe0;
|
||||
m_dma[Channel].mode = bool(BIT(m_dma[Channel].len, 31));
|
||||
}
|
||||
|
||||
// TODO: following regs are supposedly single byte, but HW still accesses them as dword, is it a liability?
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::dir_r()
|
||||
{
|
||||
return m_dma[Channel].dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* SB_**DIR (transfer direction)
|
||||
* ---x (0) root -> G2 device RAM
|
||||
* (1) root <- G2 device RAM
|
||||
*/
|
||||
template <u8 Channel> void dc_g2if_device::dir_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (ACCESSING_BITS_0_7)
|
||||
m_dma[Channel].dir = bool(BIT(data, 0));
|
||||
}
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::tsel_r()
|
||||
{
|
||||
return m_dma[Channel].tsel;
|
||||
}
|
||||
|
||||
/*
|
||||
* SB_**TSEL (trigger select)
|
||||
* -x-- SUSPend enable
|
||||
* --x- (0) CPU trigger (along with st_w '1'),
|
||||
* (1) HW trigger (with external pin/irq mechanism)
|
||||
* ---x External pin enable
|
||||
*/
|
||||
template <u8 Channel> void dc_g2if_device::tsel_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
m_dma[Channel].tsel = data & 7;
|
||||
m_dma[Channel].hw_trigger = bool(BIT(m_dma[Channel].tsel, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::en_r()
|
||||
{
|
||||
return m_dma[Channel].enable;
|
||||
}
|
||||
|
||||
/*
|
||||
* SB_**EN
|
||||
* ---x DMA enable
|
||||
* (0) mask
|
||||
* (1) enabled
|
||||
* Note: DMA transfer is aborted if this is written with a 0.
|
||||
*/
|
||||
template <u8 Channel> void dc_g2if_device::en_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
m_dma[Channel].enable = bool(BIT(data, 0));
|
||||
// TODO: suppresses an in-progress DMA if this is disabled
|
||||
}
|
||||
}
|
||||
|
||||
template <u8 Channel> u32 dc_g2if_device::st_r()
|
||||
{
|
||||
return m_dma[Channel].in_progress & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SB_**ST
|
||||
* ---x DMA start/status
|
||||
* (r) (0) DMA isn't running (1) DMA is in-progress
|
||||
* (w) (1) starts a DMA (if hw_trigger is '0')
|
||||
*/
|
||||
template <u8 Channel> void dc_g2if_device::st_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
if (m_dma[Channel].start == true)
|
||||
{
|
||||
LOGWARN("%s: DMA%d attempt to start an in-flight\n", machine().describe_context(), Channel);
|
||||
return;
|
||||
}
|
||||
|
||||
m_dma[Channel].start = bool(BIT(data, 0));
|
||||
|
||||
if (m_dma[Channel].enable && m_dma[Channel].start && m_dma[Channel].hw_trigger == false)
|
||||
{
|
||||
LOGDMA("%s: DMA%d root=%08x g2=%08x dir=G2%sroot (%d)\n size=%08x (len=%08x) mode=DMA %s\n",
|
||||
machine().describe_context(), Channel,
|
||||
m_dma[Channel].root_addr, m_dma[Channel].g2_addr, m_dma[Channel].dir ? "->" : "<-",
|
||||
m_dma[Channel].dir,
|
||||
m_dma[Channel].size, m_dma[Channel].len, m_dma[Channel].mode ? "end" : "restart"
|
||||
);
|
||||
dma_execute(Channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --x- ---- (r/o) DMA request input state (from external bus?)
|
||||
// ---x ---- (r/o) DMA suspend/stop status (active low)
|
||||
// ---- ---x (w) DMA suspend request
|
||||
template <u8 Channel> u32 dc_g2if_device::susp_r()
|
||||
{
|
||||
return (m_dma[Channel].in_progress == false) << 4;
|
||||
}
|
||||
|
||||
template <u8 Channel> void dc_g2if_device::susp_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
// TODO: unemulated suspend mode
|
||||
if (data & 1)
|
||||
{
|
||||
LOGWARN("%s: DMA%d suspend write %08x %08x\n",
|
||||
machine().describe_context(),
|
||||
Channel, data, mem_mask
|
||||
);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// Misc. registers
|
||||
//**************************************************************************
|
||||
|
||||
// SB_G2ID
|
||||
// 0001 ---- Holly v1.0
|
||||
// ---- 0011 G2 version
|
||||
u32 dc_g2if_device::g2id_r()
|
||||
{
|
||||
LOGWARN("%s: read ID\n", machine().describe_context());
|
||||
return 0x12;
|
||||
}
|
||||
|
||||
// SB_G2APRO
|
||||
// xxxx xxxx xxxx xxxx ---- ---- ---- ---- Unlock register (must be == 0x4659)
|
||||
// ---- ---- ---- ---- -xxx xxxx ---- ---- Top range (start address)
|
||||
// ---- ---- ---- ---- ---- ---- -xxx xxxx Bottom range (end address)
|
||||
// all channels follows this ruleset
|
||||
void dc_g2if_device::g2apro_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (mem_mask != 0xffffffff)
|
||||
{
|
||||
LOGWARN("%s: g2apro_w attempt to write %08x with a non-dword (mem_mask=%08x)\n", machine().describe_context(), data, mem_mask);
|
||||
return;
|
||||
}
|
||||
const u16 security_code = data >> 16;
|
||||
|
||||
if (security_code != 0x4659)
|
||||
{
|
||||
LOGWARN("%s: g2apro_w attempt to write %08x without satisfying security code condition\n", machine().describe_context(), data);
|
||||
return;
|
||||
}
|
||||
|
||||
const u16 top_range = (data & 0x7f00) >> 8;
|
||||
const u16 bottom_range = (data & 0x7f);
|
||||
|
||||
m_g2apro.top_addr = (top_range << 20) | 0x08000000;
|
||||
m_g2apro.bottom_addr = (bottom_range << 20) | 0x080fffff;
|
||||
|
||||
LOGILLEGAL("%s: g2apro_w set top=%08x bottom=%08x (%08x)\n",
|
||||
machine().describe_context(),
|
||||
m_g2apro.top_addr, m_g2apro.bottom_addr, data
|
||||
);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// DMA implementation
|
||||
//**************************************************************************
|
||||
|
||||
inline bool dc_g2if_device::root_address_check(u32 offset)
|
||||
{
|
||||
const u8 area = (offset >> 26) & 7;
|
||||
// root iA is generated by accessing outside System RAM or texture/framebuffer RAM
|
||||
return area == 1 || area == 3;
|
||||
}
|
||||
|
||||
inline bool dc_g2if_device::g2_address_check(u32 offset)
|
||||
{
|
||||
const u8 area = (offset >> 26) & 7;
|
||||
// g2 iA is generated by accessing outside:
|
||||
// - area == 0 for AD/E1/E2 buses
|
||||
// - area == 5 for DD
|
||||
return area == 0 || area == 5;
|
||||
}
|
||||
|
||||
inline bool dc_g2if_device::root_overflow_check(u32 offset, u8 channel)
|
||||
{
|
||||
bool result = offset >= m_g2apro.top_addr && offset <= m_g2apro.bottom_addr;
|
||||
if (result == false)
|
||||
LOGILLEGAL("DMA%d overflow abort root=%08x\n", channel, offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void dc_g2if_device::dma_execute(u8 channel)
|
||||
{
|
||||
u32 src, dst, index, transfer_size;
|
||||
dst = m_dma[channel].g2_addr;
|
||||
src = m_dma[channel].root_addr;
|
||||
|
||||
// Punt if attempts to go beyond the allocated buses
|
||||
// TODO: should require two extra cycles for fetching addresses first
|
||||
if (!root_address_check(src) || !g2_address_check(dst))
|
||||
{
|
||||
LOGILLEGAL("%s: DMA%d illegal address attempt root=%08x g2=%08x\n",
|
||||
machine().describe_context(),
|
||||
channel, src, dst
|
||||
);
|
||||
m_dma[channel].in_progress = false;
|
||||
m_dma[channel].start = false;
|
||||
m_dma[channel].enable = false;
|
||||
m_error_ia_w(channel, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
transfer_size = m_dma[channel].size;
|
||||
/* 0 rounding size = 32 Mbytes */
|
||||
if (transfer_size == 0) { transfer_size = 0x200000; }
|
||||
|
||||
if (m_dma[channel].dir == 1)
|
||||
std::swap(src, dst);
|
||||
|
||||
// notify that a DMA is in progress
|
||||
// ofc this should rather transfer one word at a time,
|
||||
// we currently don't do that for performance reasons ...
|
||||
m_dma[channel].in_progress = true;
|
||||
|
||||
bool dma_result = true;
|
||||
|
||||
for (; index < transfer_size; index += 2)
|
||||
{
|
||||
// assert that root address is inside the g2apro range
|
||||
if (!root_overflow_check(m_dma[channel].dir ? dst : src, channel))
|
||||
{
|
||||
dma_result = false;
|
||||
break;
|
||||
}
|
||||
// TODO: raise debug signals if SB_G2DSTO / SB_G2TRTO aren't respected
|
||||
// Shouldn't matter for AICA RAM,
|
||||
// it does in loopchk g2 test 0304 when it tries to write to
|
||||
// expansion bus (where nothing lies on stock DC)
|
||||
m_host_space->write_word(dst, m_host_space->read_word(src));
|
||||
src += 2;
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
// update the params
|
||||
// Note: if you trigger an instant DMA IRQ trigger, sfz3ugd doesn't play any BGM.
|
||||
// G2 bus is 16 bits @ 25 MHz according to Fig. 2-1
|
||||
// TODO: reported limit output for AICA DMA is set at 11.3MB/s while the others at 24.0/26.0
|
||||
// bus contention ftw ...
|
||||
const attotime dma_time = attotime::from_ticks(index / 2, clock());
|
||||
|
||||
m_dma[channel].g2_addr = dst;
|
||||
m_dma[channel].root_addr = src;
|
||||
// TODO: how len copes with updates?
|
||||
m_dma[channel].len = 0;
|
||||
// clear mask flag if the DMA transfer mode is in End mode
|
||||
// (Restart mode leaves this set to true)
|
||||
if (m_dma[channel].mode == true)
|
||||
m_dma[channel].enable = false;
|
||||
|
||||
m_dma[channel].end_timer->adjust(dma_time, dma_result);
|
||||
}
|
||||
|
||||
/*
|
||||
* normal_ist: SB_G2DTNRM & SB_ISTNRM
|
||||
* (triggers a DMA if selected irq in former gets triggered)
|
||||
* ext_ist: SB_G2DTEXT & SB_ISTEXT
|
||||
* (triggers a DMA if external pin is triggered)
|
||||
*/
|
||||
void dc_g2if_device::hw_irq_trigger_hs(u32 normal_ist, u32 ext_ist)
|
||||
{
|
||||
// TODO: is latter requiring .tsel bit 0 == 1?
|
||||
bool hw_ist_enable = normal_ist || ext_ist;
|
||||
|
||||
if (hw_ist_enable == false)
|
||||
return;
|
||||
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
if (m_dma[ch].hw_trigger & m_dma[ch].enable)
|
||||
{
|
||||
LOGHWTRIG("HW trigger channel %d (ISTNRM=%08x ISTEXT=%08x)\n", ch, normal_ist, ext_ist);
|
||||
dma_execute(ch);
|
||||
}
|
||||
}
|
||||
}
|
105
src/mame/machine/dc_g2if.h
Normal file
105
src/mame/machine/dc_g2if.h
Normal file
@ -0,0 +1,105 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Angelo Salese
|
||||
/**************************************************************************************************
|
||||
|
||||
Sega Dreamcast G2 System Bus I/F
|
||||
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_DC_G2IF_H
|
||||
#define MAME_MACHINE_DC_G2IF_H
|
||||
|
||||
#pragma once
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
class dc_g2if_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
dc_g2if_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
template <typename T> void set_host_space(T &&tag, int index) { m_host_space.set_tag(std::forward<T>(tag), index); }
|
||||
auto int_cb() { return m_int_w.bind(); }
|
||||
auto error_ia_cb() { return m_error_ia_w.bind(); }
|
||||
auto error_ov_cb() { return m_error_ov_w.bind(); }
|
||||
|
||||
void amap(address_map &map);
|
||||
|
||||
void hw_irq_trigger_hs(u32 normal_ist, u32 ext_ist);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
//virtual void device_validity_check(validity_checker &valid) const override;
|
||||
//virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
private:
|
||||
required_address_space m_host_space;
|
||||
devcb_write8 m_int_w;
|
||||
devcb_write8 m_error_ia_w;
|
||||
devcb_write8 m_error_ov_w;
|
||||
|
||||
struct {
|
||||
u32 g2_addr;
|
||||
u32 root_addr;
|
||||
u32 len;
|
||||
u32 size;
|
||||
bool mode;
|
||||
bool dir;
|
||||
bool enable;
|
||||
bool in_progress;
|
||||
bool start;
|
||||
u8 tsel;
|
||||
bool hw_trigger;
|
||||
emu_timer *end_timer;
|
||||
} m_dma[4];
|
||||
|
||||
struct {
|
||||
u32 bottom_addr;
|
||||
u32 top_addr;
|
||||
} m_g2apro;
|
||||
|
||||
template <u8 Channel> void channel_map(address_map &map);
|
||||
|
||||
template <u8 Channel> u32 stag_r();
|
||||
template <u8 Channel> void stag_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 star_r();
|
||||
template <u8 Channel> void star_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 len_r();
|
||||
template <u8 Channel> void len_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 dir_r();
|
||||
template <u8 Channel> void dir_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 tsel_r();
|
||||
template <u8 Channel> void tsel_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 en_r();
|
||||
template <u8 Channel> void en_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 st_r();
|
||||
template <u8 Channel> void st_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
template <u8 Channel> u32 susp_r();
|
||||
template <u8 Channel> void susp_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
|
||||
void dma_execute(u8 channel);
|
||||
bool root_address_check(u32 offset);
|
||||
bool g2_address_check(u32 offset);
|
||||
bool root_overflow_check(u32 offset, u8 channel);
|
||||
|
||||
u32 g2id_r();
|
||||
void g2apro_w(offs_t offset, u32 data, u32 mem_mask = ~0);
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(DC_G2IF, dc_g2if_device)
|
||||
|
||||
#endif // MAME_MACHINE_DC_G2IF_H
|
@ -6,6 +6,12 @@
|
||||
|
||||
DC home console hardware overrides (GD-ROM drive etc)
|
||||
|
||||
TODO:
|
||||
- Convert to actual G1 I/F;
|
||||
- gdrom_alt_status is identical to normal status except that "but it does not clear DMA status information when it is accessed";
|
||||
- Verify unimplemented behaviours via tests;
|
||||
|
||||
Old notes, consultation only:
|
||||
c230048 - 5 is written, want 6
|
||||
c0d9d9e - where bad happens, from routine @ c0da260
|
||||
|
||||
@ -13,20 +19,28 @@
|
||||
|
||||
cfffee0 - stack location when bad happens
|
||||
|
||||
TODO:
|
||||
- gdrom_alt_status is identical to normal status except that "but it does not clear DMA status information when it is accessed"
|
||||
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cdrom.h"
|
||||
#include "debugger.h"
|
||||
//#include "debugger.h"
|
||||
#include "includes/dc.h"
|
||||
#include "cpu/sh/sh4.h"
|
||||
#include "sound/aica.h"
|
||||
#include "includes/dccons.h"
|
||||
|
||||
#define ATAPI_CYCLES_PER_SECTOR (5000) // TBD for Dreamcast
|
||||
// TODO: fine grain this value
|
||||
#define ATAPI_CYCLES_PER_SECTOR (5000)
|
||||
|
||||
#define LOG_WARN (1U << 1)
|
||||
#define LOG_XFER (1U << 2) // log ATAPI transfers
|
||||
|
||||
#define VERBOSE (LOG_WARN)
|
||||
//#define LOG_OUTPUT_STREAM std::cout
|
||||
#include "logmacro.h"
|
||||
|
||||
#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
|
||||
#define LOGXFER(...) LOGMASKED(LOG_XFER, __VA_ARGS__)
|
||||
|
||||
WRITE_LINE_MEMBER(dc_cons_state::ata_interrupt)
|
||||
{
|
||||
@ -44,18 +58,18 @@ TIMER_CALLBACK_MEMBER(dc_cons_state::atapi_xfer_end )
|
||||
|
||||
atapi_timer->adjust(attotime::never);
|
||||
|
||||
printf("atapi_xfer_end atapi_xferlen = %d\n", atapi_xferlen );
|
||||
|
||||
//osd_printf_debug("ATAPI: xfer_end. xferlen = %d\n", atapi_xferlen);
|
||||
LOGXFER("atapi_xfer_end atapi_xferlen = %d\n", atapi_xferlen );
|
||||
|
||||
m_ata->write_dmack(1);
|
||||
atapi_xfercomplete = 0;
|
||||
|
||||
// TODO: dispatch transfers one step at a time instead of the full block
|
||||
while (atapi_xferlen > 0 )
|
||||
{
|
||||
struct sh4_ddt_dma ddtdata;
|
||||
|
||||
// get a sector from the SCSI device
|
||||
for (int i = 0; i < 2048/2; i++)
|
||||
for (int i = 0; i < 2048 / 2; i++)
|
||||
{
|
||||
int d = m_ata->read_dma();
|
||||
sector_buffer[ i*2 ] = d & 0xff;
|
||||
@ -67,13 +81,15 @@ TIMER_CALLBACK_MEMBER(dc_cons_state::atapi_xfer_end )
|
||||
|
||||
// perform the DMA
|
||||
ddtdata.destination = atapi_xferbase; // destination address
|
||||
ddtdata.length = 2048/4;
|
||||
ddtdata.length = 2048 / 4;
|
||||
ddtdata.size = 4;
|
||||
ddtdata.buffer = sector_buffer;
|
||||
ddtdata.direction=1; // 0 source to buffer, 1 buffer to destination
|
||||
ddtdata.channel= 0;
|
||||
ddtdata.mode= -1; // copy from/to buffer
|
||||
printf("ATAPI: DMA one sector to %x, %x remaining\n", atapi_xferbase, atapi_xferlen);
|
||||
ddtdata.direction = 1; // 0 source to buffer, 1 buffer to destination
|
||||
ddtdata.channel = 0;
|
||||
ddtdata.mode = -1; // copy from/to buffer
|
||||
LOGXFER("G1 I/F ATAPI: DMA one sector to %x, %x remaining\n",
|
||||
atapi_xferbase, atapi_xferlen
|
||||
);
|
||||
m_maincpu->sh4_dma_ddt(&ddtdata);
|
||||
|
||||
atapi_xferbase += 2048;
|
||||
@ -81,14 +97,16 @@ TIMER_CALLBACK_MEMBER(dc_cons_state::atapi_xfer_end )
|
||||
|
||||
m_ata->write_dmack(0);
|
||||
|
||||
g1bus_regs[SB_GDST]=0;
|
||||
g1bus_regs[SB_GDST] = 0;
|
||||
dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_GDROM;
|
||||
dc_update_interrupt_status();
|
||||
}
|
||||
|
||||
void dc_cons_state::dreamcast_atapi_init()
|
||||
{
|
||||
atapi_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dc_cons_state::atapi_xfer_end),this));
|
||||
atapi_timer = machine().scheduler().timer_alloc(
|
||||
timer_expired_delegate(FUNC(dc_cons_state::atapi_xfer_end), this)
|
||||
);
|
||||
atapi_timer->adjust(attotime::never);
|
||||
save_item(NAME(atapi_xferlen));
|
||||
save_item(NAME(atapi_xferbase));
|
||||
@ -119,8 +137,9 @@ uint32_t dc_cons_state::dc_mess_g1_ctrl_r(offs_t offset)
|
||||
switch(offset)
|
||||
{
|
||||
case SB_GDSTARD:
|
||||
printf("G1CTRL: GDSTARD %08x\n", atapi_xferbase); // Hello Kitty reads here
|
||||
machine().debug_break();
|
||||
// TODO: one of the Hello Kitty (identify which) reads there
|
||||
logerror("G1CTRL: GDSTARD %08x\n", atapi_xferbase);
|
||||
//machine().debug_break();
|
||||
return atapi_xferbase;
|
||||
case SB_GDST:
|
||||
break;
|
||||
@ -135,8 +154,8 @@ uint32_t dc_cons_state::dc_mess_g1_ctrl_r(offs_t offset)
|
||||
// 0 - check in progress, BIOS data summed, G1 ATA area blocked (read FFFFFFFFh)
|
||||
return 3;
|
||||
default:
|
||||
printf("G1CTRL: Unmapped read %08x\n", 0x5f7400+offset*4);
|
||||
machine().debug_break();
|
||||
LOGWARN("G1CTRL: Unmapped read %08x\n", 0x5f7400 + offset * 4);
|
||||
//machine().debug_break();
|
||||
break;
|
||||
}
|
||||
return g1bus_regs[offset];
|
||||
@ -148,27 +167,29 @@ void dc_cons_state::dc_mess_g1_ctrl_w(offs_t offset, uint32_t data, uint32_t mem
|
||||
// osd_printf_verbose("G1CTRL: [%08x=%x] write %x to %x, mask %x\n", 0x5f7400+reg*4, dat, data, offset, mem_mask);
|
||||
switch (offset)
|
||||
{
|
||||
case SB_GDST:
|
||||
if (data & 1 && g1bus_regs[SB_GDEN] == 1) // 0 -> 1
|
||||
{
|
||||
if (g1bus_regs[SB_GDDIR] == 0)
|
||||
case SB_GDST:
|
||||
if (data & 1 && g1bus_regs[SB_GDEN] == 1) // 0 -> 1
|
||||
{
|
||||
printf("G1CTRL: unsupported transfer\n");
|
||||
return;
|
||||
if (g1bus_regs[SB_GDDIR] == 0)
|
||||
{
|
||||
// TODO: write to GD-ROM, shouldn't happen unless "special" condition occurs
|
||||
// (implies a debug/development device?)
|
||||
LOGWARN("%s: G1 I/F illegal direction transfer\n", machine().describe_context());
|
||||
return;
|
||||
}
|
||||
|
||||
atapi_xferbase = g1bus_regs[SB_GDSTAR];
|
||||
//atapi_timer->adjust(m_maincpu->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048))));
|
||||
/* 12x * 75 Hz = 0,00(1) secs per sector */
|
||||
/* TODO: make DMA to be single step */
|
||||
atapi_timer->adjust(attotime::from_usec(1111*atapi_xferlen/2048));
|
||||
// atapi_regs[ATAPI_REG_SAMTAG] = GDROM_PAUSE_STATE | 0x80;
|
||||
}
|
||||
break;
|
||||
|
||||
atapi_xferbase = g1bus_regs[SB_GDSTAR];
|
||||
//atapi_timer->adjust(m_maincpu->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048))));
|
||||
/* 12x * 75 Hz = 0,00(1) secs per sector */
|
||||
/* TODO: make DMA to be single step */
|
||||
atapi_timer->adjust(attotime::from_usec(1111*atapi_xferlen/2048));
|
||||
// atapi_regs[ATAPI_REG_SAMTAG] = GDROM_PAUSE_STATE | 0x80;
|
||||
}
|
||||
break;
|
||||
|
||||
case SB_GDLEN:
|
||||
atapi_xferlen = data;
|
||||
break;
|
||||
case SB_GDLEN:
|
||||
atapi_xferlen = data;
|
||||
break;
|
||||
|
||||
/*
|
||||
The following register is involved in BIOS checksum protection system.
|
||||
@ -195,12 +216,12 @@ void dc_cons_state::dc_mess_g1_ctrl_w(offs_t offset, uint32_t data, uint32_t mem
|
||||
|
||||
all described above works the same way in all HOLLY/CLX2-based systems - Dreamcast, Naomi 1/2, Atomiswave, SystemSP
|
||||
*/
|
||||
case SB_SECUR_EADR:
|
||||
if (data==0 || data==0x001fffff || data==0x42fe)
|
||||
{
|
||||
// atapi_regs[ATAPI_REG_SAMTAG] = GDROM_PAUSE_STATE | 0x80;
|
||||
printf("Unlocking GD-ROM! %x\n", data);
|
||||
}
|
||||
break;
|
||||
case SB_SECUR_EADR:
|
||||
if (data==0 || data==0x001fffff || data==0x42fe)
|
||||
{
|
||||
// atapi_regs[ATAPI_REG_SAMTAG] = GDROM_PAUSE_STATE | 0x80;
|
||||
logerror("%s: Unlocking GD-ROM %x\n", machine().describe_context(), data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,18 @@
|
||||
#include "emu.h"
|
||||
#include "gdrom.h"
|
||||
|
||||
#define LOG_WARN (1U << 1)
|
||||
#define LOG_CMD (1U << 2)
|
||||
#define LOG_XFER (1U << 3)
|
||||
|
||||
#define VERBOSE (LOG_WARN | LOG_CMD)
|
||||
//#define LOG_OUTPUT_STREAM std::cout
|
||||
#include "logmacro.h"
|
||||
|
||||
#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
|
||||
#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__)
|
||||
#define LOGXFER(...) LOGMASKED(LOG_XFER, __VA_ARGS__)
|
||||
|
||||
#define GDROM_BUSY_STATE 0x00
|
||||
#define GDROM_PAUSE_STATE 0x01
|
||||
#define GDROM_STANDBY_STATE 0x02
|
||||
@ -162,29 +174,29 @@ void gdrom_device::ExecCommand()
|
||||
case 0x11: // REQ_MODE
|
||||
m_phase = SCSI_PHASE_DATAIN;
|
||||
m_status_code = SCSI_STATUS_CODE_GOOD;
|
||||
printf("REQ_MODE %02x %02x %02x %02x %02x %02x\n",
|
||||
LOGCMD("REQ_MODE %02x %02x %02x %02x %02x %02x\n",
|
||||
command[0], command[1],
|
||||
command[2], command[3],
|
||||
command[4], command[5]);
|
||||
command[4], command[5]
|
||||
);
|
||||
// if (SCSILengthFromUINT8( &command[ 4 ] ) < 32) return -1;
|
||||
transferOffset = command[2];
|
||||
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
|
||||
break;
|
||||
|
||||
case 0x12: // SET_MODE
|
||||
logerror("GDROM: SET_MODE\n");
|
||||
m_phase = SCSI_PHASE_DATAOUT;
|
||||
m_status_code = SCSI_STATUS_CODE_GOOD;
|
||||
//transferOffset = command[2];
|
||||
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
|
||||
printf("SET_MODE %02x %02x\n",command[2],command[4]);
|
||||
LOGCMD("SET_MODE %02x %02x\n", command[2], command[4]);
|
||||
break;
|
||||
|
||||
case 0x30: // CD_READ
|
||||
if (command[1] & 1)
|
||||
{
|
||||
fatalerror("GDROM: MSF mode used for CD_READ, unsupported\n");
|
||||
m_transfer_length = 0;
|
||||
throw emu_fatalerror("GDROM: MSF mode used for CD_READ, unsupported");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -196,15 +208,19 @@ void gdrom_device::ExecCommand()
|
||||
|
||||
if (read_type != 2) // mode 1
|
||||
{
|
||||
fatalerror("GDROM: Unhandled read_type %d\n", read_type);
|
||||
throw emu_fatalerror("GDROM: Unhandled read_type %d", read_type);
|
||||
}
|
||||
|
||||
if (data_select != 2) // just sector data
|
||||
{
|
||||
fatalerror("GDROM: Unhandled data_select %d\n", data_select);
|
||||
throw emu_fatalerror("GDROM: Unhandled data_select %d", data_select);
|
||||
}
|
||||
|
||||
printf("GDROM: CD_READ at LBA %x for %d blocks (%d bytes, read type %d, data select %d)\n", m_lba, m_blocks, m_blocks * m_sector_bytes, read_type, data_select);
|
||||
LOGCMD("CD_READ %02x %02x\n", command[2], command[4]);
|
||||
LOGCMD(" LBA %x for %d blocks (%d bytes, read type %d, data select %d)\n",
|
||||
m_lba, m_blocks,
|
||||
m_blocks * m_sector_bytes, read_type, data_select
|
||||
);
|
||||
|
||||
if (m_num_subblocks > 1)
|
||||
{
|
||||
@ -230,7 +246,8 @@ void gdrom_device::ExecCommand()
|
||||
// READ TOC (GD-ROM ver.)
|
||||
case 0x14:
|
||||
{
|
||||
int start_trk = command[2];// ok?
|
||||
// TODO: is this correct?
|
||||
int start_trk = command[2];
|
||||
int end_trk = cdrom_get_last_track(m_cdrom);
|
||||
int length;
|
||||
int allocation_length = SCSILengthFromUINT16( &command[ 3 ] );
|
||||
@ -286,7 +303,7 @@ void gdrom_device::ExecCommand()
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("command 0x40: unhandled subchannel request\n");
|
||||
LOGWARN("command 0x40: unhandled subchannel request\n");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -308,22 +325,22 @@ void gdrom_device::ReadData( uint8_t *data, int dataLength )
|
||||
switch ( command[0] )
|
||||
{
|
||||
case 0x11: // REQ_MODE
|
||||
printf("REQ_MODE: dataLength %d\n", dataLength);
|
||||
LOGCMD("REQ_MODE dataLength %d\n", dataLength);
|
||||
memcpy(data, &GDROM_Cmd11_Reply[transferOffset], (dataLength >= 32-transferOffset) ? 32-transferOffset : dataLength);
|
||||
break;
|
||||
|
||||
case 0x30: // CD_READ
|
||||
logerror("GDROM: read %x dataLength, \n", dataLength);
|
||||
LOGCMD("CD_READ read %x dataLength,\n", dataLength);
|
||||
if ((m_cdrom) && (m_blocks))
|
||||
{
|
||||
while (dataLength > 0)
|
||||
{
|
||||
if (!cdrom_read_data(m_cdrom, m_lba, tmp_buffer, CD_TRACK_MODE1))
|
||||
{
|
||||
logerror("GDROM: CD read error!\n");
|
||||
LOGWARN("CD read error!\n");
|
||||
}
|
||||
|
||||
logerror("True LBA: %d, buffer half: %d\n", m_lba, m_cur_subblock * m_sector_bytes);
|
||||
LOGXFER("True LBA: %d, buffer half: %d\n", m_lba, m_cur_subblock * m_sector_bytes);
|
||||
|
||||
memcpy(data, &tmp_buffer[m_cur_subblock * m_sector_bytes], m_sector_bytes);
|
||||
|
||||
@ -350,77 +367,81 @@ void gdrom_device::ReadData( uint8_t *data, int dataLength )
|
||||
our internal routines for tracks use "0" as track 1. That probably
|
||||
should be fixed...
|
||||
*/
|
||||
printf("GDROM: READ TOC, format = %d time=%d\n", command[2]&0xf,(command[1]>>1)&1);
|
||||
LOGCMD("READ TOC format = %d time=%d\n",
|
||||
command[2] & 0xf, (command[1] >> 1) & 1
|
||||
);
|
||||
switch (command[2] & 0x0f)
|
||||
{
|
||||
case 0: // normal
|
||||
{
|
||||
int start_trk;
|
||||
int end_trk;
|
||||
int len;
|
||||
int in_len;
|
||||
int dptr;
|
||||
uint32_t tstart;
|
||||
|
||||
start_trk = command[2];
|
||||
if( start_trk == 0 )
|
||||
{
|
||||
int start_trk;
|
||||
int end_trk;
|
||||
int len;
|
||||
int in_len;
|
||||
int dptr;
|
||||
uint32_t tstart;
|
||||
|
||||
start_trk = command[2];
|
||||
if( start_trk == 0 )
|
||||
{
|
||||
start_trk = 1;
|
||||
}
|
||||
|
||||
end_trk = cdrom_get_last_track(m_cdrom);
|
||||
len = (end_trk * 8) + 2;
|
||||
|
||||
// the returned TOC DATA LENGTH must be the full amount,
|
||||
// regardless of how much we're able to pass back due to in_len
|
||||
dptr = 0;
|
||||
data[dptr++] = (len>>8) & 0xff;
|
||||
data[dptr++] = (len & 0xff);
|
||||
data[dptr++] = 1;
|
||||
data[dptr++] = end_trk;
|
||||
|
||||
if( start_trk == 0xaa )
|
||||
{
|
||||
end_trk = 0xaa;
|
||||
}
|
||||
|
||||
in_len = command[3]<<8 | command[4];
|
||||
|
||||
for (i = start_trk; i <= end_trk; i++)
|
||||
{
|
||||
int cdrom_track = i;
|
||||
if( cdrom_track != 0xaa )
|
||||
{
|
||||
cdrom_track--;
|
||||
}
|
||||
|
||||
if( dptr >= in_len )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
data[dptr++] = 0;
|
||||
data[dptr++] = cdrom_get_adr_control(m_cdrom, cdrom_track);
|
||||
data[dptr++] = i;
|
||||
data[dptr++] = 0;
|
||||
|
||||
tstart = cdrom_get_track_start(m_cdrom, cdrom_track);
|
||||
if ((command[1]&2)>>1)
|
||||
tstart = lba_to_msf(tstart);
|
||||
data[dptr++] = (tstart>>24) & 0xff;
|
||||
data[dptr++] = (tstart>>16) & 0xff;
|
||||
data[dptr++] = (tstart>>8) & 0xff;
|
||||
data[dptr++] = (tstart & 0xff);
|
||||
}
|
||||
start_trk = 1;
|
||||
}
|
||||
|
||||
end_trk = cdrom_get_last_track(m_cdrom);
|
||||
len = (end_trk * 8) + 2;
|
||||
|
||||
// the returned TOC DATA LENGTH must be the full amount,
|
||||
// regardless of how much we're able to pass back due to in_len
|
||||
dptr = 0;
|
||||
data[dptr++] = (len>>8) & 0xff;
|
||||
data[dptr++] = (len & 0xff);
|
||||
data[dptr++] = 1;
|
||||
data[dptr++] = end_trk;
|
||||
|
||||
if( start_trk == 0xaa )
|
||||
{
|
||||
end_trk = 0xaa;
|
||||
}
|
||||
|
||||
in_len = command[3]<<8 | command[4];
|
||||
|
||||
for (i = start_trk; i <= end_trk; i++)
|
||||
{
|
||||
int cdrom_track = i;
|
||||
if( cdrom_track != 0xaa )
|
||||
{
|
||||
cdrom_track--;
|
||||
}
|
||||
|
||||
if( dptr >= in_len )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
data[dptr++] = 0;
|
||||
data[dptr++] = cdrom_get_adr_control(m_cdrom, cdrom_track);
|
||||
data[dptr++] = i;
|
||||
data[dptr++] = 0;
|
||||
|
||||
tstart = cdrom_get_track_start(m_cdrom, cdrom_track);
|
||||
if ((command[1]&2)>>1)
|
||||
tstart = lba_to_msf(tstart);
|
||||
data[dptr++] = (tstart>>24) & 0xff;
|
||||
data[dptr++] = (tstart>>16) & 0xff;
|
||||
data[dptr++] = (tstart>>8) & 0xff;
|
||||
data[dptr++] = (tstart & 0xff);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logerror("GDROM: Unhandled READ TOC format %d\n", command[2]&0xf);
|
||||
LOGWARN("Unhandled READ TOC format %d\n", command[2]&0xf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x71:
|
||||
LOGCMD("SYS_REQ_SECU\n");
|
||||
memcpy(data, &GDROM_Cmd71_Reply[0], sizeof(GDROM_Cmd71_Reply));
|
||||
if (is_real_gdrom_disc)
|
||||
data[10] = 0x1f; // needed by dimm board firmware
|
||||
@ -534,7 +555,8 @@ void gdrom_device::device_start()
|
||||
void gdrom_device::process_buffer()
|
||||
{
|
||||
atapi_hle_device::process_buffer();
|
||||
m_sector_number = 0x80 | GDROM_PAUSE_STATE; /// HACK: find out when this should be updated
|
||||
// HACK: find out when this should be updated
|
||||
m_sector_number = 0x80 | GDROM_PAUSE_STATE;
|
||||
}
|
||||
|
||||
void gdrom_device::signature()
|
||||
|
@ -1,407 +0,0 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Angelo Salese, Olivier Galibert, David Haywood, Samuele Zannoli, R. Belmont, ElSemi
|
||||
/***************************************************************************
|
||||
|
||||
Per-game specific JVS settings / idle loop skips for the MAME Naomi driver.
|
||||
|
||||
suchie3: check bp c0a6458 (might be protection related)
|
||||
|
||||
tetkiwam: check bp c09613a
|
||||
|
||||
vtennis: check wpset dee3ec8,8,w,wpdata==0xa8804000
|
||||
|
||||
vtennis2: check bp c020130 / wpset c013ff0,f,w,wpdata==0x3f800000 -> 0xc020434 (test mode)
|
||||
|
||||
smarinef: put cabinet in STD mode, bp c027968, wpset c0e66a6,4,w
|
||||
|
||||
|
||||
hotd2: bp 0xc0ba235, modify work RAM 0xc9c35e8 to be zero, bpclear
|
||||
|
||||
hotd2o: bp 0xc0ba1f6, modify work RAM 0xc9c35a8 to be zero, bpclear
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "includes/dc.h"
|
||||
#include "includes/naomi.h"
|
||||
#include "sound/aica.h"
|
||||
|
||||
uint64_t naomi_state::naomi_biose_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc04173c)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
//m_maincpu->spin_until_interrupt();
|
||||
// else
|
||||
// printf("%08x\n", m_maincpu->pc());
|
||||
|
||||
return dc_ram[0x2ad238/8];
|
||||
}
|
||||
|
||||
uint64_t naomi_state::naomi_biosh_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc045ffc)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
|
||||
// printf("%08\n", m_maincpu->pc());
|
||||
|
||||
return dc_ram[0x2b0600/8];
|
||||
}
|
||||
|
||||
uint64_t naomi_state::naomi2_biose_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc04637c)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
//m_maincpu->spin_until_interrupt();
|
||||
// else
|
||||
// printf("%08x\n", m_maincpu->pc());
|
||||
|
||||
return dc_ram[0x2b0600/8];
|
||||
}
|
||||
|
||||
uint8_t naomi_state::asciihex_to_dec(uint8_t in)
|
||||
{
|
||||
if (in>=0x30 && in<=0x39)
|
||||
{
|
||||
return in - 0x30;
|
||||
}
|
||||
else
|
||||
if (in>=0x41 && in<=0x46)
|
||||
{
|
||||
return in - 0x37;
|
||||
}
|
||||
/*
|
||||
else
|
||||
if (in>=0x61 && in<=0x66)
|
||||
{
|
||||
return in - 0x57;
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
fatalerror("unexpected value in asciihex_to_dec\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// development helper function
|
||||
void naomi_state::create_pic_from_retdat()
|
||||
{
|
||||
{
|
||||
memory_region * rgn_hexregion = memregion("pichex");
|
||||
memory_region * rgn_retregion = memregion("picreturn");
|
||||
memory_region * rgn_newregion = memregion("pic");
|
||||
int outcount = 0;
|
||||
|
||||
if (rgn_hexregion && rgn_newregion)
|
||||
{
|
||||
uint8_t* hexregion = rgn_hexregion->base();
|
||||
uint8_t* newregion = rgn_newregion->base();
|
||||
|
||||
|
||||
int hexoffs = 0;
|
||||
int line;
|
||||
|
||||
hexoffs += 0x11; // skip first line // :020000040000FA
|
||||
|
||||
for (line=0;line<0x200;line++)
|
||||
{
|
||||
int offs2;
|
||||
|
||||
hexoffs+= 0x1; // skip :
|
||||
hexoffs+= 0x8; // skip line # (:20xxxxxx incrementing in 0x2000)
|
||||
|
||||
for (offs2=0;offs2<0x20;offs2++)
|
||||
{
|
||||
uint8_t ascii1 = hexregion[hexoffs+0];
|
||||
uint8_t ascii2 = hexregion[hexoffs+1];
|
||||
uint8_t dec1 = asciihex_to_dec(ascii1);
|
||||
uint8_t dec2 = asciihex_to_dec(ascii2);
|
||||
uint8_t val = dec1 << 4 | dec2;
|
||||
|
||||
//printf("%02x%02x", ascii1, ascii2);
|
||||
|
||||
printf("%02x", val);
|
||||
|
||||
newregion[outcount] = val;
|
||||
|
||||
hexoffs+=2;
|
||||
outcount++;
|
||||
}
|
||||
|
||||
hexoffs+=0x4; // skip running checksum + newline
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (rgn_retregion && rgn_newregion)
|
||||
{
|
||||
uint8_t* retregion = rgn_retregion->base();
|
||||
uint8_t* newregion = rgn_newregion->base();
|
||||
|
||||
|
||||
int i;
|
||||
printf("string 1 (key1)\n");
|
||||
for (i=0;i<7;i++)
|
||||
{
|
||||
printf("%02x %02x\n", newregion[0x780+i*2], retregion[0x31+i]);
|
||||
|
||||
newregion[0x780+i*2] = retregion[0x31+i]; // patch with extracted data
|
||||
}
|
||||
|
||||
printf("string 2 (key2)\n");
|
||||
for (i=0;i<7;i++)
|
||||
{
|
||||
printf("%02x %02x\n", newregion[0x7a0+i*2], retregion[0x29+i]);
|
||||
|
||||
newregion[0x7a0+i*2] = retregion[0x29+i]; // patch with extracted data
|
||||
}
|
||||
|
||||
printf("string 3 (filename)\n");
|
||||
for (i=0;i<7;i++)
|
||||
{
|
||||
printf("%02x %02x\n", newregion[0x7c0+i*2], retregion[0x21+i]);
|
||||
|
||||
newregion[0x7c0+i*2] = retregion[0x21+i]; // patch with extracted data
|
||||
}
|
||||
|
||||
printf("string 4 (filename?)\n");
|
||||
for (i=0;i<7;i++)
|
||||
{
|
||||
printf("%02x %02x\n", newregion[0x7e0+i*2], retregion[0x19+i]);
|
||||
|
||||
newregion[0x7e0+i*2] = retregion[0x19+i]; // patch with extracted data
|
||||
}
|
||||
}
|
||||
|
||||
if (rgn_newregion)
|
||||
{
|
||||
uint8_t* newregion = rgn_newregion->base();
|
||||
|
||||
FILE *fp;
|
||||
char filename[256];
|
||||
sprintf(filename,"picbin_%s", machine().system().name);
|
||||
fp=fopen(filename, "w+b");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(newregion, outcount, 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
printf("wrote %04x bytes\n", outcount);
|
||||
}
|
||||
|
||||
// hex dumps end with
|
||||
//:10400000000000000000000000000000000082002E
|
||||
//:00000001FF
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void naomi_state::set_drc_options()
|
||||
{
|
||||
m_maincpu->sh2drc_set_options(SH2DRC_STRICT_VERIFY | SH2DRC_STRICT_PCREL);
|
||||
m_maincpu->sh2drc_add_fastram(0x00000000, 0x001fffff, true, m_rombase);
|
||||
m_maincpu->sh2drc_add_fastram(0x0c000000, 0x0dffffff, false, dc_ram);
|
||||
}
|
||||
|
||||
void naomi_state::init_naomi()
|
||||
{
|
||||
//m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2ad238, 0xc2ad23f, read64smo_delegate(*this, FUNC(naomi_state::naomi_biose_idle_skip_r)); // rev e bios
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2b0600, 0xc2b0607, read64smo_delegate(*this, FUNC(naomi_state::naomi_biosh_idle_skip_r))); // rev h bios
|
||||
|
||||
set_drc_options();
|
||||
create_pic_from_retdat();
|
||||
}
|
||||
|
||||
void naomi2_state::init_naomi2()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2b0600, 0xc2b0607, read64smo_delegate(*this, FUNC(naomi_state::naomi2_biose_idle_skip_r))); // rev e bios
|
||||
|
||||
set_drc_options();
|
||||
create_pic_from_retdat();
|
||||
}
|
||||
|
||||
INPUT_CHANGED_MEMBER(naomi_state::naomi_mp_w)
|
||||
{
|
||||
m_mp_mux = newval;
|
||||
}
|
||||
|
||||
CUSTOM_INPUT_MEMBER(naomi_state::naomi_mp_r)
|
||||
{
|
||||
uint8_t retval = 0;
|
||||
|
||||
int port = 0;
|
||||
for (int i = 0x80; i >= 0x08; i >>= 1, port++)
|
||||
{
|
||||
if (m_mp_mux & i)
|
||||
retval |= m_mp[port].read_safe(0);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
CUSTOM_INPUT_MEMBER(naomi_state::suchie3_mp_r)
|
||||
{
|
||||
uint8_t retval = 0;
|
||||
|
||||
int port = 0;
|
||||
for (int i = 0x80; i >= 0x08; i >>= 1, port++)
|
||||
{
|
||||
if (m_mp_mux & i)
|
||||
{
|
||||
// KEY1 and KEY5 are swapped
|
||||
if (port == 0)
|
||||
retval |= m_mp[4].read_safe(0);
|
||||
else if (port == 4)
|
||||
retval |= m_mp[0].read_safe(0);
|
||||
else
|
||||
retval |= m_mp[port].read_safe(0);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
CUSTOM_INPUT_MEMBER(naomi_state::naomi_kb_r)
|
||||
{
|
||||
// TODO: player 2 input reading
|
||||
uint8_t retval = 0;
|
||||
static const char *const keynames[] =
|
||||
{
|
||||
"P1.ROW0", "P1.ROW1", "P1.ROW2", "P1.ROW3", "P1.ROW4"
|
||||
};
|
||||
|
||||
for(int i=0;i<5;i++)
|
||||
{
|
||||
uint32_t row;
|
||||
|
||||
// read the current row
|
||||
row = ioport(keynames[i])->read();
|
||||
|
||||
// if anything is pressed, convert the 32-bit raw value to keycode
|
||||
if(row != 0)
|
||||
{
|
||||
// base value x20
|
||||
retval = i * 0x20;
|
||||
for(int j=0;j<32;j++)
|
||||
{
|
||||
if(row & 1 << j)
|
||||
return retval + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void naomi_state::init_naomi_mp()
|
||||
{
|
||||
//m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2ad238, 0xc2ad23f, read64smo_delegate(*this, FUNC(naomi_state::naomi_biose_idle_skip_r)); // rev e bios
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2b0600, 0xc2b0607, read64smo_delegate(*this, FUNC(naomi_state::naomi_biosh_idle_skip_r))); // rev h bios
|
||||
m_mp_mux = 0;
|
||||
|
||||
set_drc_options();
|
||||
create_pic_from_retdat();
|
||||
}
|
||||
|
||||
void naomi_state::init_naomigd()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2ad238, 0xc2ad23f, read64smo_delegate(*this, FUNC(naomi_state::naomi_biose_idle_skip_r))); // rev e bios
|
||||
//m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2b0600, 0xc2b0607, read64smo_delegate(*this, FUNC(naomi_state::naomi_biosh_idle_skip_r))); // rev h bios
|
||||
|
||||
set_drc_options();
|
||||
create_pic_from_retdat();
|
||||
}
|
||||
|
||||
void naomi_state::init_naomigd_mp()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2ad238, 0xc2ad23f, read64smo_delegate(*this, FUNC(naomi_state::naomi_biose_idle_skip_r))); // rev e bios
|
||||
//m_maincpu->space(AS_PROGRAM).install_read_handler(0xc2b0600, 0xc2b0607, read64smo_delegate(*this, FUNC(naomi_state::naomi_biosh_idle_skip_r))); // rev h bios
|
||||
m_mp_mux = 0;
|
||||
|
||||
set_drc_options();
|
||||
create_pic_from_retdat();
|
||||
}
|
||||
|
||||
|
||||
uint64_t naomi_state::naomigd_ggxxsla_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0x0c0c9adc)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
|
||||
return dc_ram[0x1aae18/8];
|
||||
}
|
||||
|
||||
void naomi_state::init_ggxxsla()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc1aae18, 0xc1aae1f, read64smo_delegate(*this, FUNC(naomi_state::naomigd_ggxxsla_idle_skip_r)));
|
||||
init_naomigd();
|
||||
}
|
||||
|
||||
uint64_t naomi_state::naomigd_ggxx_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc0b5c3c) // or 0xc0bab0c
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
|
||||
return dc_ram[0x1837b8/8];
|
||||
}
|
||||
|
||||
|
||||
void naomi_state::init_ggxx()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc1837b8, 0xc1837bf, read64smo_delegate(*this, FUNC(naomi_state::naomigd_ggxx_idle_skip_r)));
|
||||
init_naomigd();
|
||||
}
|
||||
|
||||
uint64_t naomi_state::naomigd_ggxxrl_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc0b84bc) // or 0xc0bab0c
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
|
||||
//printf("%08x\n", m_maincpu->pc());
|
||||
|
||||
return dc_ram[0x18d6c8/8];
|
||||
}
|
||||
|
||||
void naomi_state::init_ggxxrl()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc18d6c8, 0xc18d6cf, read64smo_delegate(*this, FUNC(naomi_state::naomigd_ggxxrl_idle_skip_r)));
|
||||
init_naomigd();
|
||||
}
|
||||
|
||||
/* at least speeds up the annoying copyright screens ;-) */
|
||||
uint64_t naomi_state::naomigd_sfz3ugd_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc36a2dc)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
|
||||
return dc_ram[0x5dc900/8];
|
||||
}
|
||||
|
||||
void naomi_state::init_sfz3ugd()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xc5dc900, 0xc5dc907, read64smo_delegate(*this, FUNC(naomi_state::naomigd_sfz3ugd_idle_skip_r)));
|
||||
init_naomigd();
|
||||
}
|
||||
|
||||
|
||||
uint64_t naomi_state::hotd2_idle_skip_r()
|
||||
{
|
||||
// if (m_maincpu->pc()==0xc0cfcbc)
|
||||
// m_maincpu->spin_until_time(attotime::from_usec(500));
|
||||
//m_maincpu->spin_until_interrupt();
|
||||
// else
|
||||
// printf("%08x\n", m_maincpu->pc());
|
||||
|
||||
return dc_ram[0xa25fb8/8];
|
||||
}
|
||||
|
||||
void naomi_state::init_hotd2()
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_handler(0xca25fb8, 0xca25fbf, read64smo_delegate(*this, FUNC(naomi_state::hotd2_idle_skip_r)));
|
||||
set_drc_options();
|
||||
}
|
||||
|
||||
// f355 PC=0xc065f7c RAM=0xc26dafc
|
@ -2,6 +2,15 @@
|
||||
// copyright-holders:Olivier Galibert
|
||||
/*
|
||||
Dreamcast video emulation
|
||||
|
||||
TODO:
|
||||
- Needs break-down into sub-devices, as a generic rule of thumb
|
||||
TA is Holly/CLX implementation specific while CORE is ISP/TSP only.
|
||||
This will be particularly useful for PVR PMX implementations
|
||||
(atvtrack.cpp and aristmk6.cpp);
|
||||
- Remove dc_state readbacks from here;
|
||||
- Better abstraction of timers;
|
||||
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
@ -12,6 +21,26 @@
|
||||
#include "video/rgbutil.h"
|
||||
#include "rendutil.h"
|
||||
|
||||
#define LOG_WARN (1U << 1) // Show warnings
|
||||
#define LOG_TA_CMD (1U << 2) // Show TA CORE commands
|
||||
#define LOG_TA_FIFO (1U << 3) // Show TA FIFO polygon entries
|
||||
#define LOG_TA_TILE (1U << 4) // Show TA tile entries
|
||||
#define LOG_PVR_DMA (1U << 5) // Show PVR-DMA access
|
||||
#define LOG_IRQ (1U << 6) // Show irq triggers
|
||||
|
||||
#define VERBOSE (LOG_WARN | LOG_PVR_DMA)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
|
||||
#define LOGTACMD(...) LOGMASKED(LOG_TA_CMD, __VA_ARGS__)
|
||||
#define LOGTAFIFO(...) LOGMASKED(LOG_TA_FIFO, __VA_ARGS__)
|
||||
#define LOGTATILE(...) LOGMASKED(LOG_TA_TILE, __VA_ARGS__)
|
||||
#define LOGPVRDMA(...) LOGMASKED(LOG_PVR_DMA, __VA_ARGS__)
|
||||
#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__)
|
||||
|
||||
#define LIVE_YUV_VIEW 0
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(POWERVR2, powervr2_device, "powervr2", "PowerVR 2")
|
||||
|
||||
@ -82,7 +111,7 @@ void powervr2_device::ta_map(address_map &map)
|
||||
map(0x0144, 0x0147).rw(FUNC(powervr2_device::ta_list_init_r), FUNC(powervr2_device::ta_list_init_w));
|
||||
map(0x0148, 0x014b).rw(FUNC(powervr2_device::ta_yuv_tex_base_r), FUNC(powervr2_device::ta_yuv_tex_base_w));
|
||||
map(0x014c, 0x014f).rw(FUNC(powervr2_device::ta_yuv_tex_ctrl_r), FUNC(powervr2_device::ta_yuv_tex_ctrl_w));
|
||||
map(0x0150, 0x0153).rw(FUNC(powervr2_device::ta_yuv_tex_cnt_r), FUNC(powervr2_device::ta_yuv_tex_cnt_w));
|
||||
map(0x0150, 0x0153).r(FUNC(powervr2_device::ta_yuv_tex_cnt_r));
|
||||
map(0x0160, 0x0163).w(FUNC(powervr2_device::ta_list_cont_w));
|
||||
map(0x0164, 0x0167).rw(FUNC(powervr2_device::ta_next_opb_init_r), FUNC(powervr2_device::ta_next_opb_init_w));
|
||||
|
||||
@ -106,12 +135,6 @@ const int powervr2_device::pvr_parconfseq[] = {1,2,3,2,3,4,5,6,5,6,7,8,9,10,11,1
|
||||
const int powervr2_device::pvr_wordsvertex[24] = {8,8,8,8,8,16,16,8,8,8, 8, 8,8,8,8,8,16,16, 8,16,16,8,16,16};
|
||||
const int powervr2_device::pvr_wordspolygon[24] = {8,8,8,8,8, 8, 8,8,8,8,16,16,8,8,8,8, 8, 8,16,16,16,8, 8, 8};
|
||||
|
||||
#define DEBUG_FIFO_POLY (0)
|
||||
#define DEBUG_PVRTA 0
|
||||
#define DEBUG_PVRDLIST (0)
|
||||
#define DEBUG_PALRAM (0)
|
||||
#define DEBUG_PVRCTRL (0)
|
||||
|
||||
inline int32_t powervr2_device::clamp(int32_t in, int32_t min, int32_t max)
|
||||
{
|
||||
if(in < min) return min;
|
||||
@ -959,15 +982,12 @@ void powervr2_device::softreset_w(offs_t offset, uint32_t data, uint32_t mem_mas
|
||||
{
|
||||
COMBINE_DATA(&softreset);
|
||||
if (softreset & 1) {
|
||||
#if DEBUG_PVRTA
|
||||
logerror("%s: TA soft reset\n", tag());
|
||||
#endif
|
||||
LOGTACMD("TA soft reset\n");
|
||||
listtype_used=0;
|
||||
}
|
||||
if (softreset & 2) {
|
||||
#if DEBUG_PVRTA
|
||||
logerror("%s: Core Pipeline soft reset\n", tag());
|
||||
#endif
|
||||
LOGTACMD("Core Pipeline soft reset\n");
|
||||
|
||||
if (start_render_received == 1) {
|
||||
for (int a=0;a < NUM_BUFFERS;a++)
|
||||
if (grab[a].busy == 1)
|
||||
@ -977,9 +997,7 @@ void powervr2_device::softreset_w(offs_t offset, uint32_t data, uint32_t mem_mas
|
||||
}
|
||||
}
|
||||
if (softreset & 4) {
|
||||
#if DEBUG_PVRTA
|
||||
logerror("%s: sdram I/F soft reset\n", tag());
|
||||
#endif
|
||||
LOGTACMD("sdram I/F soft reset\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -987,9 +1005,8 @@ void powervr2_device::startrender_w(address_space &space, uint32_t data)
|
||||
{
|
||||
dc_state *state = machine().driver_data<dc_state>();
|
||||
g_profiler.start(PROFILER_USER1);
|
||||
#if DEBUG_PVRTA
|
||||
logerror("%s: Start render, region=%08x, params=%08x\n", tag(), region_base, param_base);
|
||||
#endif
|
||||
|
||||
LOGTACMD("Start render, region=%08x, params=%08x\n", region_base, param_base);
|
||||
|
||||
// select buffer to draw using param_base
|
||||
for (int a=0;a < NUM_BUFFERS;a++) {
|
||||
@ -1054,9 +1071,19 @@ void powervr2_device::startrender_w(address_space &space, uint32_t data)
|
||||
//if(sanitycount>2000)
|
||||
// break;
|
||||
}
|
||||
// printf("ISP START %d %d\n",sanitycount,screen().vpos());
|
||||
/* Fire ISP irq after a set amount of time TODO: timing of this */
|
||||
endofrender_timer_isp->adjust(state->m_maincpu->cycles_to_attotime(sanitycount*25 + 500000)); // hacky end of render delay for Capcom games, otherwise they works at ~1/10 speed
|
||||
|
||||
/* Fire ISP irq after a set amount of time */
|
||||
// TODO: exact timing of this
|
||||
// hacky end of render delay for Capcom games, otherwise they works at ~1/10 speed.
|
||||
// 500k is definitely too slow for them: it fires the isp/tsp completion at
|
||||
// vbl-in and expect that it completes after some time that vbl-out kicks in,
|
||||
// in order to have enough time to execute logic stuff in the meantime.
|
||||
// const u64 isp_completion = sanitycount * 25 + 500000;
|
||||
const u64 isp_completion = sanitycount * 25 + 2000000;
|
||||
LOGIRQ("[%d] ISP end of render start %d in %d cycles\n",
|
||||
screen().frame_number(), screen().vpos(), isp_completion
|
||||
);
|
||||
endofrender_timer_isp->adjust(state->m_maincpu->cycles_to_attotime(isp_completion));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1221,7 +1248,7 @@ uint32_t powervr2_device::spg_hblank_int_r()
|
||||
void powervr2_device::spg_hblank_int_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&spg_hblank_int);
|
||||
/* TODO: timer adjust */
|
||||
// TODO: timer adjust
|
||||
}
|
||||
|
||||
uint32_t powervr2_device::spg_vblank_int_r()
|
||||
@ -1364,7 +1391,7 @@ uint32_t powervr2_device::spg_status_r()
|
||||
|
||||
uint32_t vsync = ((screen().vpos() >= spg_vbstart) || (screen().vpos() < spg_vbend)) ? 0 : 1;
|
||||
uint32_t hsync = ((screen().hpos() >= spg_hbstart) || (screen().hpos() < spg_hbend)) ? 0 : 1;
|
||||
/* FIXME: following is just a wild guess */
|
||||
// FIXME: following is just a wild guess
|
||||
uint32_t blank = ((screen().vpos() >= spg_vbstart) || (screen().vpos() < spg_vbend) |
|
||||
(screen().hpos() >= spg_hbstart) || (screen().hpos() < spg_hbend)) ? 0 : 1;
|
||||
if(vo_control & 4) { blank^=1; }
|
||||
@ -1447,10 +1474,14 @@ void powervr2_device::ta_list_init_w(uint32_t data)
|
||||
tafifo_mask=7;
|
||||
tafifo_vertexwords=8;
|
||||
tafifo_listtype= DISPLAY_LIST_NONE;
|
||||
#if DEBUG_PVRTA
|
||||
logerror("%s: list init ol=(%08x, %08x) isp=(%08x, %08x), alloc=%08x obp=%08x\n",
|
||||
tag(), ta_ol_base, ta_ol_limit, ta_isp_base, ta_isp_limit, ta_alloc_ctrl, ta_next_opb_init);
|
||||
#endif
|
||||
|
||||
LOGTACMD("list init ol=(%08x, %08x) isp=(%08x, %08x), alloc=%08x obp=%08x\n",
|
||||
ta_ol_base, ta_ol_limit,
|
||||
ta_isp_base, ta_isp_limit,
|
||||
ta_alloc_ctrl,
|
||||
ta_next_opb_init
|
||||
);
|
||||
|
||||
ta_next_opb = ta_next_opb_init;
|
||||
ta_itp_current = ta_isp_base;
|
||||
alloc_ctrl_OPB_Mode = ta_alloc_ctrl & 0x100000; // 0 up 1 down
|
||||
@ -1509,12 +1540,11 @@ uint32_t powervr2_device::ta_yuv_tex_base_r()
|
||||
void powervr2_device::ta_yuv_tex_base_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&ta_yuv_tex_base);
|
||||
logerror("%s: ta_yuv_tex_base = %08x\n", tag(), ta_yuv_tex_base);
|
||||
|
||||
// Writes causes a reset in YUV FIFO pipeline
|
||||
ta_yuv_index = 0;
|
||||
ta_yuv_x = 0;
|
||||
ta_yuv_y = 0;
|
||||
|
||||
ta_yuv_u_ptr = 0;
|
||||
ta_yuv_v_ptr = 0;
|
||||
}
|
||||
|
||||
uint32_t powervr2_device::ta_yuv_tex_ctrl_r()
|
||||
@ -1525,27 +1555,22 @@ uint32_t powervr2_device::ta_yuv_tex_ctrl_r()
|
||||
void powervr2_device::ta_yuv_tex_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&ta_yuv_tex_ctrl);
|
||||
ta_yuv_x_size = ((ta_yuv_tex_ctrl & 0x3f)+1)*16;
|
||||
ta_yuv_y_size = (((ta_yuv_tex_ctrl>>8) & 0x3f)+1)*16;
|
||||
logerror("%s: ta_yuv_tex_ctrl = %08x\n", tag(), ta_yuv_tex_ctrl);
|
||||
if(ta_yuv_tex_ctrl & 0x01010000)
|
||||
fatalerror("YUV with setting %08x",ta_yuv_tex_ctrl);
|
||||
|
||||
ta_yuv_v_size = (((ta_yuv_tex_ctrl >> 8) & 0x3f) + 1) * 16;
|
||||
ta_yuv_u_size = ((ta_yuv_tex_ctrl & 0x3f) + 1) * 16;
|
||||
|
||||
if (ta_yuv_tex_ctrl & 0x01010000)
|
||||
throw emu_fatalerror("YUV422 mode selected %08x", ta_yuv_tex_ctrl);
|
||||
}
|
||||
|
||||
#include "debugger.h"
|
||||
/* TODO */
|
||||
// TODO: unemulated YUV macroblock live count, nothing seems to use it?
|
||||
uint32_t powervr2_device::ta_yuv_tex_cnt_r()
|
||||
{
|
||||
machine().debug_break();
|
||||
if (!machine().side_effects_disabled())
|
||||
LOGWARN("%s yuv_tex_cnt read!", machine().describe_context());
|
||||
return ta_yuv_tex_cnt;
|
||||
}
|
||||
|
||||
void powervr2_device::ta_yuv_tex_cnt_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
machine().debug_break();
|
||||
COMBINE_DATA(&ta_yuv_tex_cnt);
|
||||
}
|
||||
|
||||
void powervr2_device::ta_list_cont_w(uint32_t data)
|
||||
{
|
||||
if(data & 0x80000000) {
|
||||
@ -1700,7 +1725,8 @@ void powervr2_device::sb_pdst_w(address_space &space, offs_t offset, uint32_t da
|
||||
uint32_t old = m_pvr_dma.start & 1;
|
||||
m_pvr_dma.start = sb_pdst & 1;
|
||||
|
||||
if(((old & 1) == 0) && m_pvr_dma.flag && m_pvr_dma.start && ((m_pvr_dma.sel & 1) == 0)) // 0 -> 1
|
||||
// 0 -> 1 transition starts the DMA
|
||||
if(((old & 1) == 0) && m_pvr_dma.flag && m_pvr_dma.start && ((m_pvr_dma.sel & 1) == 0))
|
||||
pvr_dma_execute(space);
|
||||
}
|
||||
|
||||
@ -1717,35 +1743,35 @@ void powervr2_device::sb_pdapro_w(offs_t offset, uint32_t data, uint32_t mem_mas
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::transfer_opaque_list_irq)
|
||||
{
|
||||
// printf("OPLST %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] EOXFER OPLST %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
irq_cb(EOXFER_OPLST_IRQ);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::transfer_opaque_modifier_volume_list_irq)
|
||||
{
|
||||
// printf("OPMV %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] EOXFER OPMV %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
irq_cb(EOXFER_OPMV_IRQ);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::transfer_translucent_list_irq)
|
||||
{
|
||||
// printf("TRLST %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] EOXFER TRLST %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
irq_cb(EOXFER_TRLST_IRQ);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::transfer_translucent_modifier_volume_list_irq)
|
||||
{
|
||||
// printf("TRMV %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] EOXFER TRMV %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
irq_cb(EOXFER_TRMV_IRQ);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::transfer_punch_through_list_irq)
|
||||
{
|
||||
// printf("PTLST %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] EOXFER PTLST %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
irq_cb(EOXFER_PTLST_IRQ);
|
||||
}
|
||||
@ -1847,7 +1873,7 @@ void powervr2_device::process_ta_fifo()
|
||||
memcpy(poly_base_color, tafifo_buff + 4, 4 * sizeof(float));
|
||||
memset(poly_offs_color, 0, sizeof(poly_offs_color));
|
||||
}
|
||||
memcpy(poly_last_mode_2_base_color, poly_base_color, sizeof(poly_last_mode_2_base_color));
|
||||
memcpy(poly_last_mode_2_base_color, poly_base_color, sizeof(poly_last_mode_2_base_color));
|
||||
break;
|
||||
case 3:
|
||||
memcpy(poly_base_color, poly_last_mode_2_base_color, sizeof(poly_base_color));
|
||||
@ -1870,54 +1896,55 @@ void powervr2_device::process_ta_fifo()
|
||||
// here we should generate the data for the various tiles
|
||||
// for now, just interpret their meaning
|
||||
if (paratype == 0)
|
||||
{ // end of list
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose("Para Type 0 End of List\n");
|
||||
#endif
|
||||
{
|
||||
LOGTATILE("Para Type 0 End of List\n");
|
||||
|
||||
/* Process transfer FIFO done irqs here */
|
||||
/* FIXME: timing of these */
|
||||
//printf("%d %d\n",tafifo_listtype,screen().vpos());
|
||||
// FIXME: timing of these
|
||||
switch (tafifo_listtype)
|
||||
{
|
||||
case DISPLAY_LIST_OPAQUE: machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_opaque_list_irq), this)); break;
|
||||
case DISPLAY_LIST_OPAQUE_MOD: machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_opaque_modifier_volume_list_irq), this)); break;
|
||||
case DISPLAY_LIST_TRANS: machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_translucent_list_irq), this)); break;
|
||||
case DISPLAY_LIST_TRANS_MOD: machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_translucent_modifier_volume_list_irq), this)); break;
|
||||
case DISPLAY_LIST_PUNCH_THROUGH: machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_punch_through_list_irq), this)); break;
|
||||
case DISPLAY_LIST_OPAQUE:
|
||||
machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_opaque_list_irq), this));
|
||||
break;
|
||||
case DISPLAY_LIST_OPAQUE_MOD:
|
||||
machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_opaque_modifier_volume_list_irq), this));
|
||||
break;
|
||||
case DISPLAY_LIST_TRANS:
|
||||
machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_translucent_list_irq), this));
|
||||
break;
|
||||
case DISPLAY_LIST_TRANS_MOD:
|
||||
machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_translucent_modifier_volume_list_irq), this));
|
||||
break;
|
||||
case DISPLAY_LIST_PUNCH_THROUGH:
|
||||
machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(powervr2_device::transfer_punch_through_list_irq), this));
|
||||
break;
|
||||
}
|
||||
tafifo_listtype= DISPLAY_LIST_NONE; // no list being received
|
||||
tafifo_listtype = DISPLAY_LIST_NONE; // no list being received
|
||||
listtype_used |= (2+8);
|
||||
}
|
||||
else if (paratype == 1)
|
||||
{ // user tile clip
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose("Para Type 1 User Tile Clip\n");
|
||||
osd_printf_verbose(" (%d , %d)-(%d , %d)\n", tafifo_buff[4], tafifo_buff[5], tafifo_buff[6], tafifo_buff[7]);
|
||||
#endif
|
||||
{
|
||||
LOGTATILE("Para Type 1 User Tile Clip\n");
|
||||
LOGTATILE(" (%d , %d)-(%d , %d)\n", tafifo_buff[4], tafifo_buff[5], tafifo_buff[6], tafifo_buff[7]);
|
||||
}
|
||||
else if (paratype == 2)
|
||||
{ // object list set
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose("Para Type 2 Object List Set at %08x\n", tafifo_buff[1]);
|
||||
osd_printf_verbose(" (%d , %d)-(%d , %d)\n", tafifo_buff[4], tafifo_buff[5], tafifo_buff[6], tafifo_buff[7]);
|
||||
#endif
|
||||
{
|
||||
LOGTATILE("Para Type 2 Object List Set at %08x\n", tafifo_buff[1]);
|
||||
LOGTATILE(" (%d , %d)-(%d , %d)\n", tafifo_buff[4], tafifo_buff[5], tafifo_buff[6], tafifo_buff[7]);
|
||||
}
|
||||
else if (paratype == 3)
|
||||
{
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose("Para Type %x Unknown!\n", tafifo_buff[0]);
|
||||
#endif
|
||||
LOGWARN("Para Type %x Unknown!\n", tafifo_buff[0]);
|
||||
}
|
||||
else
|
||||
{ // global parameter or vertex parameter
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose("Para Type %d", paratype);
|
||||
LOGTATILE("Para Type %d", paratype);
|
||||
if (paratype == 7)
|
||||
osd_printf_verbose(" End of Strip %d", endofstrip);
|
||||
LOGTATILE(" End of Strip %d", endofstrip);
|
||||
if (listtype_used & 3)
|
||||
osd_printf_verbose(" List Type %d", listtype);
|
||||
osd_printf_verbose("\n");
|
||||
#endif
|
||||
LOGTATILE(" List Type %d", listtype);
|
||||
LOGTATILE("\n");
|
||||
|
||||
// set type of list currently being received
|
||||
if ((paratype == 4) || (paratype == 5) || (paratype == 6))
|
||||
@ -1963,61 +1990,49 @@ void powervr2_device::process_ta_fifo()
|
||||
vqcompressed=(tafifo_buff[3] >> 30) & 1;
|
||||
strideselect=(tafifo_buff[3] >> 25) & 1;
|
||||
paletteselector=(tafifo_buff[3] >> 21) & 0x3F;
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Texture at %08x format %d\n", (tafifo_buff[3] & 0x1FFFFF) << 3, pixelformat);
|
||||
#endif
|
||||
|
||||
LOGTATILE(" Texture at %08x format %d\n", (tafifo_buff[3] & 0x1FFFFF) << 3, pixelformat);
|
||||
}
|
||||
if (paratype == 4)
|
||||
{ // polygon or mv
|
||||
if ((tafifo_listtype == DISPLAY_LIST_OPAQUE_MOD) ||
|
||||
(tafifo_listtype == DISPLAY_LIST_TRANS_MOD))
|
||||
{
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Modifier Volume\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Polygon\n");
|
||||
#endif
|
||||
}
|
||||
{
|
||||
LOGTATILE(" %s\n",
|
||||
((tafifo_listtype == DISPLAY_LIST_OPAQUE_MOD) ||
|
||||
(tafifo_listtype == DISPLAY_LIST_TRANS_MOD)) ? "Modifier Volume" : "Polygon"
|
||||
);
|
||||
}
|
||||
if (paratype == 5)
|
||||
{ // quad
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Sprite\n");
|
||||
#endif
|
||||
LOGTATILE(" Sprite\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (paratype == 7)
|
||||
{ // vertex
|
||||
if (tafifo_listtype < 0 || tafifo_listtype >= DISPLAY_LIST_COUNT) {
|
||||
logerror("PowerVR2 unrecognized list type %d\n", tafifo_listtype);
|
||||
LOGWARN("unrecognized list type %d\n", tafifo_listtype);
|
||||
return;
|
||||
}
|
||||
struct poly_group *grp = rd->groups + tafifo_listtype;
|
||||
if ((tafifo_listtype == DISPLAY_LIST_OPAQUE_MOD) ||
|
||||
(tafifo_listtype == DISPLAY_LIST_TRANS_MOD))
|
||||
{
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Vertex modifier volume");
|
||||
osd_printf_verbose(" A(%f,%f,%f) B(%f,%f,%f) C(%f,%f,%f)", u2f(tafifo_buff[1]), u2f(tafifo_buff[2]),
|
||||
u2f(tafifo_buff[3]), u2f(tafifo_buff[4]), u2f(tafifo_buff[5]), u2f(tafifo_buff[6]), u2f(tafifo_buff[7]),
|
||||
u2f(tafifo_buff[8]), u2f(tafifo_buff[9]));
|
||||
osd_printf_verbose("\n");
|
||||
#endif
|
||||
LOGTATILE(" Vertex modifier volume");
|
||||
LOGTATILE(" A(%f,%f,%f) B(%f,%f,%f) C(%f,%f,%f)\n",
|
||||
u2f(tafifo_buff[1]), u2f(tafifo_buff[2]), u2f(tafifo_buff[3]),
|
||||
u2f(tafifo_buff[4]), u2f(tafifo_buff[5]), u2f(tafifo_buff[6]),
|
||||
u2f(tafifo_buff[7]), u2f(tafifo_buff[8]), u2f(tafifo_buff[9])
|
||||
);
|
||||
}
|
||||
else if (global_paratype == 5)
|
||||
{
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Vertex sprite");
|
||||
osd_printf_verbose(" A(%f,%f,%f) B(%f,%f,%f) C(%f,%f,%f) D(%f,%f,)", u2f(tafifo_buff[1]), u2f(tafifo_buff[2]),
|
||||
u2f(tafifo_buff[3]), u2f(tafifo_buff[4]), u2f(tafifo_buff[5]), u2f(tafifo_buff[6]), u2f(tafifo_buff[7]),
|
||||
u2f(tafifo_buff[8]), u2f(tafifo_buff[9]), u2f(tafifo_buff[10]), u2f(tafifo_buff[11]));
|
||||
osd_printf_verbose("\n");
|
||||
#endif
|
||||
LOGTATILE(" Vertex sprite");
|
||||
LOGTATILE(" A(%f,%f,%f) B(%f,%f,%f) C(%f,%f,%f) D(%f,%f,)\n",
|
||||
u2f(tafifo_buff[1]), u2f(tafifo_buff[2]), u2f(tafifo_buff[3]),
|
||||
u2f(tafifo_buff[4]), u2f(tafifo_buff[5]), u2f(tafifo_buff[6]),
|
||||
u2f(tafifo_buff[7]), u2f(tafifo_buff[8]), u2f(tafifo_buff[9]),
|
||||
u2f(tafifo_buff[10]), u2f(tafifo_buff[11])
|
||||
);
|
||||
|
||||
if (texture == 1)
|
||||
{
|
||||
if (rd->verts_size <= (MAX_VERTS - 6) && grp->strips_size < MAX_STRIPS)
|
||||
@ -2064,11 +2079,12 @@ void powervr2_device::process_ta_fifo()
|
||||
}
|
||||
else if (global_paratype == 4)
|
||||
{
|
||||
#if DEBUG_PVRDLIST
|
||||
osd_printf_verbose(" Vertex polygon");
|
||||
osd_printf_verbose(" V(%f,%f,%f) T(%f,%f)", u2f(tafifo_buff[1]), u2f(tafifo_buff[2]), u2f(tafifo_buff[3]), u2f(tafifo_buff[4]), u2f(tafifo_buff[5]));
|
||||
osd_printf_verbose("\n");
|
||||
#endif
|
||||
LOGTATILE(" Vertex polygon");
|
||||
LOGTATILE(" V(%f,%f,%f) T(%f,%f)\n",
|
||||
u2f(tafifo_buff[1]), u2f(tafifo_buff[2]), u2f(tafifo_buff[3]),
|
||||
u2f(tafifo_buff[4]), u2f(tafifo_buff[5])
|
||||
);
|
||||
|
||||
if (rd->verts_size <= (MAX_VERTS - 6))
|
||||
{
|
||||
float vert_offset_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
@ -2158,14 +2174,17 @@ void powervr2_device::ta_fifo_poly_w(offs_t offset, uint64_t data, uint64_t mem_
|
||||
{
|
||||
tafifo_buff[tafifo_pos]=(uint32_t)data;
|
||||
tafifo_buff[tafifo_pos+1]=(uint32_t)(data >> 32);
|
||||
#if DEBUG_FIFO_POLY
|
||||
osd_printf_debug("ta_fifo_poly_w: Unmapped write64 %08x = %x -> %08x %08x\n", 0x10000000+offset*8, data, tafifo_buff[tafifo_pos], tafifo_buff[tafifo_pos+1]);
|
||||
#endif
|
||||
LOGTAFIFO("ta_fifo_poly_w: write64 %08x = %x -> %08x %08x\n",
|
||||
0x10000000 + offset * 8,
|
||||
data,
|
||||
tafifo_buff[tafifo_pos],
|
||||
tafifo_buff[tafifo_pos + 1]
|
||||
);
|
||||
tafifo_pos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
osd_printf_debug("ta_fifo_poly_w: Unmapped write64 %08x = %x mask %x\n", 0x10000000+offset*8, data, mem_mask);
|
||||
LOGWARN("ta_fifo_poly_w: Unmapped write64 %08x = %x mask %x\n", 0x10000000+offset*8, data, mem_mask);
|
||||
}
|
||||
|
||||
tafifo_pos &= tafifo_mask;
|
||||
@ -2182,30 +2201,34 @@ TIMER_CALLBACK_MEMBER(powervr2_device::yuv_convert_end)
|
||||
yuv_timer_end->adjust(attotime::never);
|
||||
}
|
||||
|
||||
|
||||
void powervr2_device::ta_fifo_yuv_w(uint8_t data)
|
||||
{
|
||||
dc_state *state = machine().driver_data<dc_state>();
|
||||
//printf("%08x %08x\n",ta_yuv_index++,ta_yuv_tex_ctrl);
|
||||
|
||||
//popmessage("YUV fifo write %08x %08x",ta_yuv_index,ta_yuv_tex_ctrl);
|
||||
|
||||
yuv_fifo[ta_yuv_index] = data;
|
||||
ta_yuv_index++;
|
||||
|
||||
if(ta_yuv_index == 0x180)
|
||||
{
|
||||
#if LIVE_YUV_VIEW
|
||||
popmessage("YUV fifo write base=%08x ctrl=%08x (%dx%d)",
|
||||
ta_yuv_tex_base, ta_yuv_tex_ctrl,
|
||||
ta_yuv_u_size, ta_yuv_v_size
|
||||
);
|
||||
#endif
|
||||
|
||||
ta_yuv_index = 0;
|
||||
for(int y=0;y<16;y++)
|
||||
for(int y = 0; y < 16; y++)
|
||||
{
|
||||
for(int x=0;x<16;x+=2)
|
||||
for(int x = 0; x < 16; x+=2)
|
||||
{
|
||||
int dst_addr;
|
||||
int u,v,y0,y1;
|
||||
int u, v, y0, y1;
|
||||
|
||||
dst_addr = ta_yuv_tex_base;
|
||||
dst_addr+= (ta_yuv_x+x)*2;
|
||||
dst_addr+= ((ta_yuv_y+y)*320*2);
|
||||
dst_addr+= (ta_yuv_u_ptr + x) * 2;
|
||||
// pitch is given by U size (320 for luptype, 512 for ss2005/kurucham)
|
||||
dst_addr+= ((ta_yuv_v_ptr + y) * ta_yuv_u_size * 2);
|
||||
|
||||
u = yuv_fifo[0x00+(x>>1)+((y>>1)*8)];
|
||||
v = yuv_fifo[0x40+(x>>1)+((y>>1)*8)];
|
||||
@ -2219,16 +2242,16 @@ void powervr2_device::ta_fifo_yuv_w(uint8_t data)
|
||||
}
|
||||
}
|
||||
|
||||
ta_yuv_x+=16;
|
||||
if(ta_yuv_x == ta_yuv_x_size)
|
||||
ta_yuv_u_ptr += 16;
|
||||
if(ta_yuv_u_ptr == ta_yuv_u_size)
|
||||
{
|
||||
ta_yuv_x = 0;
|
||||
ta_yuv_y+=16;
|
||||
if(ta_yuv_y == ta_yuv_y_size)
|
||||
ta_yuv_u_ptr = 0;
|
||||
ta_yuv_v_ptr += 16;
|
||||
if(ta_yuv_v_ptr == ta_yuv_v_size)
|
||||
{
|
||||
ta_yuv_y = 0;
|
||||
/* TODO: timing */
|
||||
yuv_timer_end->adjust(state->m_maincpu->cycles_to_attotime((ta_yuv_x_size/16)*(ta_yuv_y_size/16)*0x180));
|
||||
ta_yuv_v_ptr = 0;
|
||||
// TODO: actual timings
|
||||
yuv_timer_end->adjust(state->m_maincpu->cycles_to_attotime((ta_yuv_u_size/16)*(ta_yuv_v_size/16)*0x180));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3385,11 +3408,9 @@ void powervr2_device::pvr_accumulationbuffer_to_framebuffer(address_space &space
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
printf("pvr_accumulationbuffer_to_framebuffer buffer to tile at %d,%d - unsupported pack mode %02x (Reserved! Don't Use!)\n",x,y,packmode);
|
||||
throw emu_fatalerror("pvr_accumulationbuffer_to_framebuffer buffer to tile at %d,%d - unsupported pack mode %02x (Reserved! Don't Use!)\n",x,y,packmode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void powervr2_device::pvr_drawframebuffer(bitmap_rgb32 &bitmap,const rectangle &cliprect)
|
||||
@ -3641,59 +3662,6 @@ void powervr2_device::pvr_drawframebuffer(bitmap_rgb32 &bitmap,const rectangle &
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG_PALRAM
|
||||
void powervr2_device::debug_paletteram()
|
||||
{
|
||||
//popmessage("%02x",pal_ram_ctrl);
|
||||
|
||||
for(int i=0;i<0x400;i++)
|
||||
{
|
||||
uint64_t pal = palette[i];
|
||||
switch(pal_ram_ctrl)
|
||||
{
|
||||
case 0: //argb1555 <- guilty gear uses this mode
|
||||
{
|
||||
//a = (pal & 0x8000)>>15;
|
||||
uint32_t r = (pal & 0x7c00)>>10;
|
||||
uint32_t g = (pal & 0x03e0)>>5;
|
||||
uint32_t b = (pal & 0x001f)>>0;
|
||||
//a = a ? 0xff : 0x00;
|
||||
m_palette->set_pen_color(i, pal5bit(r), pal5bit(g), pal5bit(b));
|
||||
}
|
||||
break;
|
||||
case 1: //rgb565
|
||||
{
|
||||
//a = 0xff;
|
||||
uint32_t r = (pal & 0xf800)>>11;
|
||||
uint32_t g = (pal & 0x07e0)>>5;
|
||||
uint32_t b = (pal & 0x001f)>>0;
|
||||
m_palette->set_pen_color(i, pal5bit(r), pal6bit(g), pal5bit(b));
|
||||
}
|
||||
break;
|
||||
case 2: //argb4444
|
||||
{
|
||||
//a = (pal & 0xf000)>>12;
|
||||
uint32_t r = (pal & 0x0f00)>>8;
|
||||
uint32_t g = (pal & 0x00f0)>>4;
|
||||
uint32_t b = (pal & 0x000f)>>0;
|
||||
m_palette->set_pen_color(i, pal4bit(r), pal4bit(g), pal4bit(b));
|
||||
}
|
||||
break;
|
||||
case 3: //argb8888
|
||||
{
|
||||
//a = (pal & 0xff000000)>>20;
|
||||
uint32_t r = (pal & 0x00ff0000)>>16;
|
||||
uint32_t g = (pal & 0x0000ff00)>>8;
|
||||
uint32_t b = (pal & 0x000000ff)>>0;
|
||||
m_palette->set_pen_color(i, r, g, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* test video end */
|
||||
|
||||
void powervr2_device::pvr_build_parameterconfig()
|
||||
@ -3726,16 +3694,24 @@ void powervr2_device::pvr_build_parameterconfig()
|
||||
pvr_parameterconfig[a] = pvr_parameterconfig[a-1];
|
||||
}
|
||||
|
||||
// TODO: these two are currently unused
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::vbin)
|
||||
{
|
||||
LOGIRQ("[%d] VBL IN %d\n", screen().frame_number(), screen().vpos());
|
||||
LOGIRQ(" VII %d VOI %d VI %d VO %d VS %d\n",
|
||||
spg_vblank_int & 0x3ff, (spg_vblank_int >> 16) & 0x3ff,
|
||||
spg_vblank & 0x3ff, (spg_vblank >> 16) & 0x3ff, (spg_load >> 16) & 0x3ff
|
||||
);
|
||||
|
||||
irq_cb(VBL_IN_IRQ);
|
||||
|
||||
//popmessage("VII %d VOI %d VI %d VO %d VS %d",spg_vblank_int & 0x3ff,(spg_vblank_int >> 16) & 0x3ff,spg_vblank & 0x3ff,(spg_vblank >> 16) & 0x3ff,(spg_load >> 16) & 0x3ff);
|
||||
// vbin_timer->adjust(screen().time_until_pos(spg_vblank_int & 0x3ff));
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::vbout)
|
||||
{
|
||||
LOGIRQ("[%d] VBL OUT %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
irq_cb(VBL_OUT_IRQ);
|
||||
|
||||
// vbout_timer->adjust(screen().time_until_pos((spg_vblank_int >> 16) & 0x3ff));
|
||||
@ -3747,17 +3723,21 @@ TIMER_CALLBACK_MEMBER(powervr2_device::hbin)
|
||||
{
|
||||
if(scanline == next_y)
|
||||
{
|
||||
LOGIRQ("[%d] HBL IN %d - (%08x)\n",
|
||||
screen().frame_number(), screen().vpos(), scanline, spg_hblank_int
|
||||
);
|
||||
irq_cb(HBL_IN_IRQ);
|
||||
next_y += spg_hblank_int & 0x3ff;
|
||||
}
|
||||
}
|
||||
else if((scanline == (spg_hblank_int & 0x3ff)) || (spg_hblank_int & 0x2000))
|
||||
{
|
||||
LOGIRQ("[%d] HBL IN %d - (%08x)\n",
|
||||
screen().frame_number(), screen().vpos(), scanline, spg_hblank_int
|
||||
);
|
||||
irq_cb(HBL_IN_IRQ);
|
||||
}
|
||||
|
||||
// printf("hbin on scanline %d\n",scanline);
|
||||
|
||||
scanline++;
|
||||
|
||||
if(scanline >= ((spg_load >> 16) & 0x3ff))
|
||||
@ -3769,17 +3749,16 @@ TIMER_CALLBACK_MEMBER(powervr2_device::hbin)
|
||||
hbin_timer->adjust(screen().time_until_pos(scanline, ((spg_hblank_int >> 16) & 0x3ff)-1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: these two aren't really called atm
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::endofrender_video)
|
||||
{
|
||||
printf("VIDEO END %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] VIDEO END %d\n", screen().frame_number(), screen().vpos());
|
||||
// endofrender_timer_video->adjust(attotime::never);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::endofrender_tsp)
|
||||
{
|
||||
printf("TSP END %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] TSP END %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
// endofrender_timer_tsp->adjust(attotime::never);
|
||||
// endofrender_timer_video->adjust(attotime::from_usec(500) );
|
||||
@ -3791,7 +3770,7 @@ TIMER_CALLBACK_MEMBER(powervr2_device::endofrender_isp)
|
||||
irq_cb(EOR_TSP_IRQ); // TSP end of render
|
||||
irq_cb(EOR_VIDEO_IRQ); // VIDEO end of render
|
||||
|
||||
// printf("ISP END %d\n",screen().vpos());
|
||||
LOGIRQ("[%d] ISP END %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
endofrender_timer_isp->adjust(attotime::never);
|
||||
// endofrender_timer_tsp->adjust(attotime::from_usec(500) );
|
||||
@ -3815,10 +3794,6 @@ uint32_t powervr2_device::screen_update(screen_device &screen, bitmap_rgb32 &bit
|
||||
// static int useframebuffer=1;
|
||||
// const rectangle &visarea = screen.visible_area();
|
||||
|
||||
#if DEBUG_PALRAM
|
||||
debug_paletteram();
|
||||
#endif
|
||||
|
||||
// copy our fake framebuffer bitmap (where things have been rendered) to the screen
|
||||
#if 0
|
||||
for (int y = visarea->min_y ; y <= visarea->max_y ; y++)
|
||||
@ -3832,10 +3807,10 @@ uint32_t powervr2_device::screen_update(screen_device &screen, bitmap_rgb32 &bit
|
||||
}
|
||||
#endif
|
||||
|
||||
bitmap.fill(rgb_t(0xff,
|
||||
(vo_border_col >> 16) & 0xff,
|
||||
//FIXME: additional Chroma bit
|
||||
bitmap.fill(rgb_t(0xff, (vo_border_col >> 16) & 0xff,
|
||||
(vo_border_col >> 8 ) & 0xff,
|
||||
(vo_border_col ) & 0xff), cliprect); //FIXME: Chroma bit?
|
||||
(vo_border_col ) & 0xff), cliprect);
|
||||
|
||||
if(!(vo_control & 8))
|
||||
pvr_drawframebuffer(bitmap, cliprect);
|
||||
@ -3846,84 +3821,16 @@ uint32_t powervr2_device::screen_update(screen_device &screen, bitmap_rgb32 &bit
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Naomi 2 attempts (TBD) */
|
||||
|
||||
uint32_t powervr2_device::pvr2_ta_r(offs_t offset)
|
||||
{
|
||||
printf("PVR2 %08x R\n", offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void powervr2_device::pvr2_ta_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
// int reg;
|
||||
// uint64_t shift;
|
||||
// uint32_t dat;
|
||||
|
||||
// reg = decode_reg_64(offset, mem_mask, &shift);
|
||||
// dat = (uint32_t)(data >> shift);
|
||||
|
||||
//printf("PVR2 %08x %08x\n",reg,dat);
|
||||
}
|
||||
|
||||
// TODO: move to specific device
|
||||
uint32_t powervr2_device::elan_regs_r(offs_t offset)
|
||||
{
|
||||
switch(offset)
|
||||
{
|
||||
case 0x00/4: // ID chip (TODO: BIOS crashes / gives a black screen with this as per now!)
|
||||
return 0xe1ad0000;
|
||||
case 0x04/4: // REVISION
|
||||
return 0x12; //or 0x01?
|
||||
case 0x10/4: // SH4 interface control (???)
|
||||
/* ---- -x-- enable second PVR */
|
||||
/* ---- --x- elan has channel 2 */
|
||||
/* ---- ---x broadcast on cs1 (?) */
|
||||
return 6;
|
||||
case 0x14/4: // SDRAM refresh register
|
||||
return 0x2029; //default 0x1429
|
||||
case 0x1c/4: // SDRAM CFG
|
||||
return 0xa7320961; //default 0xa7320961
|
||||
case 0x30/4: // Macro tiler configuration, bit 0 is enable
|
||||
return 0;
|
||||
case 0x74/4: // IRQ STAT
|
||||
return 0;
|
||||
case 0x78/4: // IRQ MASK
|
||||
return 0;
|
||||
default:
|
||||
logerror("%s %08x\n", machine().describe_context(),offset*4);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void powervr2_device::elan_regs_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
switch(offset)
|
||||
{
|
||||
default:
|
||||
logerror("%s %08x %08x W\n", machine().describe_context(),offset*4,data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void powervr2_device::pvrs_ta_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
// pvr_ta_w(offset,data,mem_mask);
|
||||
// pvr2_ta_w(offset,data,mem_mask);
|
||||
//printf("PVR2 %08x %08x\n",reg,dat);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(powervr2_device::pvr_dma_irq)
|
||||
{
|
||||
LOGIRQ("[%d] PVR DMA %d\n", screen().frame_number(), screen().vpos());
|
||||
|
||||
m_pvr_dma.start = sb_pdst = 0;
|
||||
irq_cb(DMA_PVR_IRQ);
|
||||
}
|
||||
|
||||
/* used so far by usagiym and sprtjam */
|
||||
// TODO: very inaccurate
|
||||
void powervr2_device::pvr_dma_execute(address_space &space)
|
||||
{
|
||||
dc_state *state = machine().driver_data<dc_state>();
|
||||
@ -3932,29 +3839,28 @@ void powervr2_device::pvr_dma_execute(address_space &space)
|
||||
src = m_pvr_dma.sys_addr;
|
||||
size = 0;
|
||||
|
||||
/* used so far by usagui and sprtjam*/
|
||||
printf("PVR-DMA start\n");
|
||||
printf("%08x %08x %08x\n",m_pvr_dma.pvr_addr,m_pvr_dma.sys_addr,m_pvr_dma.size);
|
||||
printf("src %s dst %08x\n",m_pvr_dma.dir ? "->" : "<-",m_pvr_dma.sel);
|
||||
LOGPVRDMA("PVR-DMA start\n");
|
||||
LOGPVRDMA("%08x %08x %08x\n",m_pvr_dma.pvr_addr, m_pvr_dma.sys_addr, m_pvr_dma.size);
|
||||
LOGPVRDMA("src %s dst %08x\n",m_pvr_dma.dir ? "->" : "<-",m_pvr_dma.sel);
|
||||
|
||||
/* Throw illegal address set */
|
||||
#if 0
|
||||
// TODO: unimplemented for now, checkable from DCLP
|
||||
#if 0
|
||||
if((m_pvr_dma.sys_addr & 0x1c000000) != 0x0c000000)
|
||||
{
|
||||
/* TODO: timing */
|
||||
irq_cb(ERR_PVRIF_ILL_ADDR_IRQ);
|
||||
m_pvr_dma.start = sb_pdst = 0;
|
||||
printf("Illegal PVR DMA set\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* 0 rounding size = 16 Mbytes */
|
||||
if(m_pvr_dma.size == 0) { m_pvr_dma.size = 0x100000; }
|
||||
|
||||
if(m_pvr_dma.dir == 0)
|
||||
{
|
||||
for(;size<m_pvr_dma.size;size+=4)
|
||||
for(;size < m_pvr_dma.size; size+=4)
|
||||
{
|
||||
space.write_dword(dst,space.read_dword(src));
|
||||
src+=4;
|
||||
@ -3963,23 +3869,42 @@ void powervr2_device::pvr_dma_execute(address_space &space)
|
||||
}
|
||||
else
|
||||
{
|
||||
for(;size<m_pvr_dma.size;size+=4)
|
||||
for(;size < m_pvr_dma.size; size+=4)
|
||||
{
|
||||
space.write_dword(src,space.read_dword(dst));
|
||||
src+=4;
|
||||
dst+=4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: do not update the params, since this DMA type doesn't support it. */
|
||||
/* TODO: timing of this */
|
||||
machine().scheduler().timer_set(state->m_maincpu->cycles_to_attotime(m_pvr_dma.size/4), timer_expired_delegate(FUNC(powervr2_device::pvr_dma_irq), this));
|
||||
// TODO: accurate timing
|
||||
machine().scheduler().timer_set(
|
||||
state->m_maincpu->cycles_to_attotime(m_pvr_dma.size/4),
|
||||
timer_expired_delegate(FUNC(powervr2_device::pvr_dma_irq), this)
|
||||
);
|
||||
}
|
||||
|
||||
INPUT_PORTS_START( powervr2 )
|
||||
PORT_START("PVR_DEBUG")
|
||||
PORT_CONFNAME( 0x01, 0x00, "Bilinear Filtering" )
|
||||
PORT_CONFSETTING( 0x00, DEF_STR( No ) )
|
||||
PORT_CONFSETTING( 0x01, DEF_STR( Yes ) )
|
||||
PORT_CONFNAME( 0x02, 0x00, "Disable Render Calls" )
|
||||
PORT_CONFSETTING( 0x00, DEF_STR( No ) )
|
||||
PORT_CONFSETTING( 0x02, DEF_STR( Yes ) )
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor powervr2_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME( powervr2 );
|
||||
}
|
||||
|
||||
powervr2_device::powervr2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, POWERVR2, tag, owner, clock),
|
||||
device_video_interface(mconfig, *this),
|
||||
irq_cb(*this),
|
||||
m_mamedebug(*this, ":MAMEDEBUG")
|
||||
: device_t(mconfig, POWERVR2, tag, owner, clock)
|
||||
, device_video_interface(mconfig, *this)
|
||||
, irq_cb(*this)
|
||||
, m_mamedebug(*this, "PVR_DEBUG")
|
||||
{
|
||||
}
|
||||
|
||||
@ -4131,13 +4056,13 @@ void powervr2_device::device_reset()
|
||||
spg_hblank_int = 0x031d0000;
|
||||
spg_vblank_int = 0x01500104;
|
||||
|
||||
tafifo_pos=0;
|
||||
tafifo_mask=7;
|
||||
tafifo_vertexwords=8;
|
||||
tafifo_listtype= DISPLAY_LIST_NONE;
|
||||
start_render_received=0;
|
||||
renderselect= -1;
|
||||
grabsel=0;
|
||||
tafifo_pos = 0;
|
||||
tafifo_mask = 7;
|
||||
tafifo_vertexwords = 8;
|
||||
tafifo_listtype = DISPLAY_LIST_NONE;
|
||||
start_render_received = 0;
|
||||
renderselect = -1;
|
||||
grabsel = 0;
|
||||
|
||||
// vbout_timer->adjust(screen().time_until_pos((spg_vblank_int >> 16) & 0x3ff));
|
||||
// vbin_timer->adjust(screen().time_until_pos(spg_vblank_int & 0x3ff));
|
||||
@ -4171,8 +4096,18 @@ void powervr2_device::pvr_scanline_timer(int vpos)
|
||||
state->m_maple->maple_hw_trigger();
|
||||
|
||||
if(vbin_line == vpos)
|
||||
{
|
||||
LOGIRQ("[%d] VBL IN %d\n", screen().frame_number(), screen().vpos());
|
||||
LOGIRQ(" VII %d VOI %d VI %d VO %d VS %d\n",
|
||||
spg_vblank_int & 0x3ff, (spg_vblank_int >> 16) & 0x3ff,
|
||||
spg_vblank & 0x3ff, (spg_vblank >> 16) & 0x3ff, (spg_load >> 16) & 0x3ff
|
||||
);
|
||||
irq_cb(VBL_IN_IRQ);
|
||||
}
|
||||
|
||||
if(vbout_line == vpos)
|
||||
{
|
||||
LOGIRQ("[%d] VBL OUT %d\n", screen().frame_number(), screen().vpos());
|
||||
irq_cb(VBL_OUT_IRQ);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ class powervr2_device : public device_t,
|
||||
public device_video_interface
|
||||
{
|
||||
public:
|
||||
powervr2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
auto irq_callback() { return irq_cb.bind(); }
|
||||
static constexpr feature_type imperfect_features() { return feature::GRAPHICS; }
|
||||
|
||||
enum { NUM_BUFFERS = 4 };
|
||||
enum {
|
||||
EOXFER_YUV_IRQ,
|
||||
@ -181,7 +185,6 @@ public:
|
||||
|
||||
uint64_t *pvr2_texture_ram;
|
||||
uint64_t *pvr2_framebuffer_ram;
|
||||
uint64_t *elan_ram;
|
||||
|
||||
uint32_t debug_dip_status;
|
||||
emu_timer *vbout_timer;
|
||||
@ -195,9 +198,6 @@ public:
|
||||
int scanline;
|
||||
int next_y;
|
||||
|
||||
powervr2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
auto irq_callback() { return irq_cb.bind(); }
|
||||
|
||||
uint32_t id_r();
|
||||
uint32_t revision_r();
|
||||
uint32_t softreset_r();
|
||||
@ -278,7 +278,6 @@ public:
|
||||
uint32_t ta_yuv_tex_ctrl_r();
|
||||
void ta_yuv_tex_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
uint32_t ta_yuv_tex_cnt_r();
|
||||
void ta_yuv_tex_cnt_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
void ta_list_cont_w(uint32_t data);
|
||||
uint32_t ta_next_opb_init_r();
|
||||
void ta_next_opb_init_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
@ -307,10 +306,7 @@ public:
|
||||
void sb_pdapro_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
uint32_t pvr2_ta_r(offs_t offset);
|
||||
void pvr2_ta_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
void pvrs_ta_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
uint32_t elan_regs_r(offs_t offset);
|
||||
void elan_regs_w(offs_t offset, uint32_t data);
|
||||
|
||||
void ta_fifo_poly_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
void ta_fifo_yuv_w(uint8_t data);
|
||||
void ta_texture_directpath0_w(offs_t offset, uint64_t data, uint64_t mem_mask = ~0);
|
||||
@ -344,6 +340,7 @@ public:
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
ioport_constructor device_input_ports() const override;
|
||||
|
||||
private:
|
||||
devcb_write8 irq_cb;
|
||||
@ -366,8 +363,8 @@ private:
|
||||
uint32_t ta_next_opb, ta_itp_current, ta_alloc_ctrl, ta_next_opb_init;
|
||||
uint32_t ta_yuv_tex_base, ta_yuv_tex_ctrl, ta_yuv_tex_cnt;
|
||||
uint32_t ta_yuv_index;
|
||||
int ta_yuv_x,ta_yuv_y;
|
||||
int ta_yuv_x_size,ta_yuv_y_size;
|
||||
int ta_yuv_u_ptr, ta_yuv_v_ptr;
|
||||
int ta_yuv_u_size, ta_yuv_v_size;
|
||||
uint8_t yuv_fifo[384];
|
||||
|
||||
// Other registers
|
||||
|
Loading…
Reference in New Issue
Block a user