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:
Angelo Salese 2022-01-17 23:30:04 +01:00 committed by GitHub
parent 7439e33919
commit 5342d0e7f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 3461 additions and 3224 deletions

View File

@ -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>

View File

@ -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",

View File

@ -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",

View File

@ -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)

View File

@ -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;
}

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -308,6 +308,7 @@ dassault.cpp
dblcrown.cpp
dblewing.cpp
dbz.cpp
dc_atomiswave.cpp
dcheese.cpp
dcon.cpp
dday.cpp

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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)

View File

@ -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 ----------*/

View 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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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));
}

View 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
View 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

View File

@ -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;
}
}

View File

@ -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()

View File

@ -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

View File

@ -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);
}
}

View File

@ -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