summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/dccons.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/dccons.cpp')
-rw-r--r--src/mame/machine/dccons.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/mame/machine/dccons.cpp b/src/mame/machine/dccons.cpp
new file mode 100644
index 00000000000..48f4bd372a6
--- /dev/null
+++ b/src/mame/machine/dccons.cpp
@@ -0,0 +1,196 @@
+// license:LGPL-2.1+
+// copyright-holders:Angelo Salese, R. Belmont
+/*
+
+ dc.c - Sega Dreamcast hardware
+
+ MESS (DC home console) hardware overrides (GD-ROM drive etc)
+
+ c230048 - 5 is written, want 6
+ c0d9d9e - where bad happens, from routine @ c0da260
+
+ c0d9d8e - R0 on return is the value to put in
+
+ 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 "includes/dc.h"
+#include "cpu/sh4/sh4.h"
+#include "sound/aica.h"
+#include "includes/dccons.h"
+
+#define ATAPI_CYCLES_PER_SECTOR (5000) // TBD for Dreamcast
+
+WRITE_LINE_MEMBER(dc_cons_state::ata_interrupt)
+{
+ if (state)
+ dc_sysctrl_regs[SB_ISTEXT] |= IST_EXT_GDROM;
+ else
+ dc_sysctrl_regs[SB_ISTEXT] &= ~IST_EXT_GDROM;
+
+ dc_update_interrupt_status();
+}
+
+TIMER_CALLBACK_MEMBER(dc_cons_state::atapi_xfer_end )
+{
+ UINT8 sector_buffer[ 4096 ];
+
+ 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);
+
+ m_ata->write_dmack(1);
+
+ while (atapi_xferlen > 0 )
+ {
+ struct sh4_ddt_dma ddtdata;
+
+ // get a sector from the SCSI device
+ for (int i = 0; i < 2048/2; i++)
+ {
+ int d = m_ata->read_dma();
+ sector_buffer[ i*2 ] = d & 0xff;
+ sector_buffer[ (i*2)+1 ] = d >> 8;
+ }
+
+ atapi_xferlen -= 2048;
+
+ // perform the DMA
+ ddtdata.destination = atapi_xferbase; // destination address
+ 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);
+ m_maincpu->sh4_dma_ddt(&ddtdata);
+
+ atapi_xferbase += 2048;
+ }
+
+ m_ata->write_dmack(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->adjust(attotime::never);
+ save_item(NAME(atapi_xferlen));
+ save_item(NAME(atapi_xferbase));
+}
+
+/*
+
+ GDROM regsters:
+
+ 5f7018: alternate status/device control
+ 5f7080: data
+ 5f7084: error/features
+ 5f7088: interrupt reason/sector count
+ 5f708c: sector number
+ 5f7090: byte control low
+ 5f7094: byte control high
+ 5f7098: drive select
+ 5f709c: status/command
+
+c002910 - ATAPI packet writes
+c002796 - aux status read after that
+c000776 - DMA triggered to c008000
+
+*/
+
+READ32_MEMBER(dc_cons_state::dc_mess_g1_ctrl_r )
+{
+ switch(offset)
+ {
+ case SB_GDSTARD:
+ printf("G1CTRL: GDSTARD %08x\n", atapi_xferbase); // Hello Kitty reads here
+ debugger_break(machine());
+ return atapi_xferbase;
+ case SB_GDST:
+ break;
+ case SB_GDLEND:
+ //debugger_break(machine());
+ return atapi_xferlen; // TODO: check me
+ default:
+ printf("G1CTRL: Unmapped read %08x\n", 0x5f7400+offset*4);
+ debugger_break(machine());
+ }
+ return g1bus_regs[offset];
+}
+
+WRITE32_MEMBER(dc_cons_state::dc_mess_g1_ctrl_w )
+{
+ g1bus_regs[offset] = data; // 5f7400+reg*4=dat
+// osd_printf_verbose("G1CTRL: [%08x=%x] write %" I64FMT "x to %x, mask %" I64FMT "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)
+ {
+ printf("G1CTRL: unsupported transfer\n");
+ 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;
+
+ case SB_GDLEN:
+ atapi_xferlen = data;
+ break;
+
+/*
+ The following register is involved in BIOS checksum protection system.
+ current understanding of its functioning based on several hardware tests:
+
+ after power on system is in "protected state":
+ - access to G1 ATA register area (5F70XX) is locked, ie GD-ROM in Dreamcast or cartridge/DIMM in arcade systems is not accessible;
+ - *any* data readed via G1 data bus (ie BIOS) is summed internally by chipset;
+ - write to GD_UNLOCK (5F74E4) register set "last address" of checksummed area;
+
+ then readed address matches with "last address" - calculated summ compared with some hardcoded value
+ if values match - system becomes in "unlocked state":
+ - G1 ATA registers unlocked;
+ - by write to GD_UNLOCK register system can be switched back to "protected state"
+
+ if values doesn't match - system switch to "locked state":
+ - similar to protected, but data summing seems not performed anymore,
+ at least write to GD_UNLOCK and "pumping" through G1 bus data chunk with valid checksumm have no effect;
+ - the only exit from this state - power off/on or reset;
+
+ actual checksum algorithm is unknown, but its supposed to be simple and weak,
+ known few modded BIOSes which succesfully passes this CRC check, because of good luck
+
+ all described above works the same way in all HOLLY/CLX2-based systems - Dreamcast, Naomi 1/2, Atomiswave, SystemSP
+*/
+ case GD_UNLOCK:
+ if (data==0 || data==0x001fffff || data==0x42fe)
+ {
+// atapi_regs[ATAPI_REG_SAMTAG] = GDROM_PAUSE_STATE | 0x80;
+ printf("Unlocking GD-ROM! %x\n", data);
+ }
+ break;
+ }
+}