mirror of
https://github.com/holub/mame
synced 2025-05-31 01:51:46 +03:00
1689 lines
29 KiB
C
1689 lines
29 KiB
C
#include "emu.h"
|
|
#include "includes/psx.h"
|
|
#include "psxcd.h"
|
|
#include "sound/spu.h"
|
|
#include "debugger.h"
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//#define debug_cdrom
|
|
//#define debug_cdrom_registers
|
|
//#define skip_reads
|
|
//#define dump_subheader
|
|
//#define disable_xa_prefetch
|
|
//#define disable_cdda_prefetch
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
enum cdrom_events
|
|
{
|
|
event_cmd_complete=0,
|
|
event_preread_sector,
|
|
event_read_sector,
|
|
event_play_sector
|
|
};
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
enum intr_status
|
|
{
|
|
intr_nointr=0,
|
|
intr_dataready,
|
|
intr_acknowledge,
|
|
intr_complete,
|
|
intr_dataend,
|
|
intr_diskerror
|
|
};
|
|
|
|
enum mode_flags
|
|
{
|
|
mode_double_speed=0x80,
|
|
mode_adpcm=0x40,
|
|
mode_size=0x20,
|
|
mode_size2=0x10,
|
|
mode_size_shift=4,
|
|
mode_size_mask=(3<<mode_size_shift),
|
|
mode_channel=0x08,
|
|
mode_report=0x04,
|
|
mode_autopause=0x02,
|
|
mode_cdda=0x01
|
|
};
|
|
|
|
enum status_f
|
|
{
|
|
status_playing=0x80,
|
|
status_seeking=0x40,
|
|
status_reading=0x20,
|
|
status_shellopen=0x10,
|
|
status_seekerror=0x04,
|
|
status_standby=0x02,
|
|
status_error=0x01
|
|
};
|
|
|
|
struct subheader
|
|
{
|
|
unsigned char file,
|
|
channel,
|
|
submode,
|
|
coding;
|
|
};
|
|
|
|
enum submode_flags
|
|
{
|
|
submode_eof=0x80,
|
|
submode_realtime=0x40,
|
|
submode_form=0x20,
|
|
submode_trigger=0x10,
|
|
submode_data=0x08,
|
|
submode_audio=0x04,
|
|
submode_video=0x02,
|
|
submode_eor=0x01
|
|
};
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
static const unsigned int max_xa_prefetch_distance=32,
|
|
max_cdda_prefetch_distance=32;
|
|
|
|
//**************************************************************************
|
|
// DEVICE DEFINITIONS
|
|
//**************************************************************************
|
|
|
|
const device_type PSXCD = &device_creator<psxcd_device>;
|
|
|
|
void psxcd_device::static_set_devname(device_t &device, const char *devname)
|
|
{
|
|
psxcd_device &psxcd = downcast<psxcd_device &>(device);
|
|
psxcd.m_devname = devname;
|
|
}
|
|
|
|
psxcd_device::psxcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
|
device_t(mconfig, PSXCD, "PSXCD", tag, owner, clock),
|
|
m_irq_handler(*this)
|
|
{
|
|
}
|
|
|
|
void psxcd_device::device_start()
|
|
{
|
|
m_irq_handler.resolve_safe();
|
|
|
|
unsigned int sysclk=machine().device<cpu_device>("maincpu")->clock()/2;
|
|
start_read_delay=(sysclk/60);
|
|
read_sector_cycles=(sysclk/75);
|
|
preread_delay=(read_sector_cycles>>2)-500;
|
|
|
|
m_sysclock = sysclk;
|
|
|
|
secleft = 0;
|
|
secsize = 2048;
|
|
res_queue = NULL;
|
|
cur_res = NULL;
|
|
open = false;
|
|
streaming = false;
|
|
sechead = 0;
|
|
sectail = 0;
|
|
secin = 0;
|
|
secskip = 0;
|
|
next_read_event = NULL;
|
|
cbp = cmdbuf;
|
|
first_open = true;
|
|
|
|
status=status_standby;
|
|
sr=8|1;
|
|
res=0;
|
|
ir=0;
|
|
mode=0;
|
|
|
|
driver = NULL;
|
|
|
|
for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
|
|
{
|
|
m_timers[i] = timer_alloc(i, NULL);
|
|
m_timerinuse[i] = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::device_reset()
|
|
{
|
|
stop_read();
|
|
open=false;
|
|
|
|
for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
|
|
{
|
|
m_timerinuse[i] = false;
|
|
}
|
|
|
|
m_cddevice = machine().device<cdrom_image_device>(m_devname);
|
|
if (m_cddevice)
|
|
{
|
|
m_cd = m_cddevice->get_cdrom_file();
|
|
|
|
if (m_cd)
|
|
{
|
|
// printf("psxcd: found disc!\n");
|
|
driver = open_mess_drv();
|
|
driver->set_machine(machine());
|
|
driver->set_cdrom_file(m_cd);
|
|
}
|
|
else
|
|
{
|
|
driver = NULL;
|
|
// printf("psxcd: Found device, but no disc\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
driver = NULL;
|
|
// printf("psxcd: Device [%s] not found!\n", m_devname);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
unsigned char psxcd_device::read_byte(const unsigned int addr)
|
|
{
|
|
unsigned char ret = 0;
|
|
|
|
switch (addr&3)
|
|
{
|
|
case 0: ret=sr; break;
|
|
case 1:
|
|
ret=res;
|
|
if ((cur_res) && (rdp<cur_res->sz))
|
|
{
|
|
res=cur_res->data[rdp++];
|
|
sr|=(1<<5);
|
|
} else
|
|
{
|
|
if ((cur_res) && (cur_res->res&0x10))
|
|
{
|
|
global_free(cur_res);
|
|
cur_res=NULL;
|
|
}
|
|
|
|
sr&=~(1<<5);
|
|
}
|
|
break;
|
|
case 2: ret=0; break;
|
|
case 3: ret=ir; break;
|
|
}
|
|
|
|
#ifdef debug_cdrom_registers
|
|
printf("cdrom: read byte %08x = %02x (PC=%x)\n",addr,ret,machine().device("maincpu")->safe_pc());
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::write_byte(const unsigned int addr, const unsigned char byte)
|
|
{
|
|
#ifdef debug_cdrom_registers
|
|
printf("cdrom: write byte %08x = %02x (PC=%x)\n",addr,byte,machine().device("maincpu")->safe_pc());
|
|
#endif
|
|
|
|
switch (addr&3)
|
|
{
|
|
case 0:
|
|
cmdmode=byte&1;
|
|
if (cmdmode==0)
|
|
{
|
|
cbp=cmdbuf;
|
|
} else
|
|
{
|
|
if (! cur_res)
|
|
{
|
|
if (cur_res) global_free(cur_res);
|
|
|
|
if (res_queue)
|
|
{
|
|
#ifdef debug_cdrom_registers
|
|
printf("cdrom: nextres\n");
|
|
#endif
|
|
|
|
cur_res=res_queue;
|
|
res_queue=res_queue->next;
|
|
ir=cur_res->res&0xf;
|
|
rdp=0;
|
|
|
|
if (cur_res->sz)
|
|
{
|
|
res=cur_res->data[rdp++];
|
|
sr|=(1<<5);
|
|
} else
|
|
{
|
|
sr&=~(1<<5);
|
|
}
|
|
} else
|
|
{
|
|
//ir=0;
|
|
cur_res=NULL;
|
|
}
|
|
}
|
|
/*else
|
|
{
|
|
if (rdp>=cur_res->sz)
|
|
{
|
|
sr&=~(1<<5);
|
|
} else
|
|
{
|
|
sr|=~(1<<5);
|
|
res=cur_res->data[rdp++];
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (cmdmode==0)
|
|
{
|
|
write_command(byte);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (cmdmode==0)
|
|
{
|
|
*cbp++=byte;
|
|
} else
|
|
{
|
|
// ?flush buffer?
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if (byte==0x07)
|
|
{
|
|
if (cur_res)
|
|
{
|
|
global_free(cur_res);
|
|
cur_res=NULL;
|
|
sr&=~(1<<5);
|
|
}
|
|
ir=0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
psxcd_device::command_info psxcd_device::cmd_table[num_commands]=
|
|
{
|
|
{ &psxcd_device::cdcmd_sync, "sync" }, // 00
|
|
{ &psxcd_device::cdcmd_nop, "nop" }, // 01
|
|
{ &psxcd_device::cdcmd_setloc, "setloc" }, // 02
|
|
{ &psxcd_device::cdcmd_play, "play" }, // 03
|
|
{ &psxcd_device::cdcmd_forward, "forward" }, // 04
|
|
{ &psxcd_device::cdcmd_backward, "backward" }, // 05
|
|
{ &psxcd_device::cdcmd_readn, "readn" }, // 06
|
|
{ &psxcd_device::cdcmd_standby, "standby" }, // 07
|
|
{ &psxcd_device::cdcmd_stop, "stop" }, // 08
|
|
{ &psxcd_device::cdcmd_pause, "pause" }, // 09
|
|
{ &psxcd_device::cdcmd_init, "init" }, // 0a
|
|
{ &psxcd_device::cdcmd_mute, "mute" }, // 0b
|
|
{ &psxcd_device::cdcmd_demute, "demute" }, // 0c
|
|
{ &psxcd_device::cdcmd_setfilter, "setfilter" }, // 0d
|
|
{ &psxcd_device::cdcmd_setmode, "setmode" }, // 0e
|
|
{ &psxcd_device::cdcmd_getparam, "getparam" }, // 0f
|
|
{ &psxcd_device::cdcmd_getlocl, "getlocl" }, // 10
|
|
{ &psxcd_device::cdcmd_getlocp, "getlocp" }, // 11
|
|
{ &psxcd_device::cdcmd_illegal, "illegal" }, // 12
|
|
{ &psxcd_device::cdcmd_gettn, "gettn" }, // 13
|
|
{ &psxcd_device::cdcmd_gettd, "gettd" }, // 14
|
|
{ &psxcd_device::cdcmd_seekl, "seekl" }, // 15
|
|
{ &psxcd_device::cdcmd_seekp, "seekp" }, // 16
|
|
{ &psxcd_device::cdcmd_illegal, "illegal" }, // 17
|
|
{ &psxcd_device::cdcmd_illegal, "illegal" }, // 18
|
|
{ &psxcd_device::cdcmd_test, "test" }, // 19
|
|
{ &psxcd_device::cdcmd_id, "id" }, // 1a
|
|
{ &psxcd_device::cdcmd_reads, "reads" }, // 1b
|
|
{ &psxcd_device::cdcmd_reset, "reset" }, // 1c
|
|
{ &psxcd_device::cdcmd_illegal, "illegal" }, // 1d
|
|
{ &psxcd_device::cdcmd_readtoc, "readtoc" }, // 1e
|
|
};
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::write_command(const unsigned char byte)
|
|
{
|
|
assert(byte<num_commands);
|
|
(this->*cmd_table[byte].func)();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::cdcmd_sync()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: sync\n");
|
|
#endif
|
|
|
|
stop_read();
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
static int open_nops=0;
|
|
|
|
void psxcd_device::cdcmd_nop()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: nop\n");
|
|
#endif
|
|
|
|
//stop_read();
|
|
|
|
if ((! open) && (driver))
|
|
{
|
|
if (open_nops==0)
|
|
{
|
|
open=driver->read_toc();
|
|
} else
|
|
{
|
|
open_nops--;
|
|
}
|
|
}
|
|
|
|
send_result(intr_complete);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_setloc()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: setloc %08x:%08x:%08x\n",
|
|
cmdbuf[0],
|
|
cmdbuf[1],
|
|
cmdbuf[2]);
|
|
#endif
|
|
|
|
stop_read();
|
|
|
|
unsigned char l[3];
|
|
l[0]=bcd_to_decimal(cmdbuf[0]);
|
|
l[1]=bcd_to_decimal(cmdbuf[1]);
|
|
l[2]=bcd_to_decimal(cmdbuf[2]);
|
|
|
|
if ((l[0]>0) || (l[1]>=2))
|
|
{
|
|
loc[0]=l[0];
|
|
loc[1]=l[1];
|
|
loc[2]=l[2];
|
|
} else
|
|
{
|
|
printf("setloc out of range: %02d:%02d:%02d\n",
|
|
l[0],l[1],l[2]);
|
|
}
|
|
|
|
send_result(intr_complete);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_play()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: play %02x %02x %02x => %d\n", loc[0], loc[1], loc[2], msf_to_sector(loc));
|
|
#endif
|
|
|
|
curpos[0]=loc[0];
|
|
curpos[1]=loc[1];
|
|
curpos[2]=loc[2];
|
|
|
|
if ((curpos[0]==0) &&
|
|
(curpos[1]==0) &&
|
|
(curpos[2]==0))
|
|
{
|
|
send_result(intr_acknowledge);
|
|
} else
|
|
{
|
|
stop_read();
|
|
start_play();
|
|
send_result(intr_acknowledge);
|
|
}
|
|
}
|
|
|
|
void psxcd_device::cdcmd_forward()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: forward\n");
|
|
#endif
|
|
}
|
|
|
|
void psxcd_device::cdcmd_backward()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: backward\n");
|
|
#endif
|
|
}
|
|
|
|
void psxcd_device::cdcmd_readn()
|
|
{
|
|
if (driver)
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: readn\n");
|
|
#endif
|
|
|
|
curpos[0]=loc[0];
|
|
curpos[1]=loc[1];
|
|
curpos[2]=loc[2];
|
|
|
|
stop_read();
|
|
start_read();
|
|
send_result(intr_complete);
|
|
} else
|
|
{
|
|
printf("read without driver\n");
|
|
send_result(intr_diskerror);
|
|
}
|
|
}
|
|
|
|
void psxcd_device::cdcmd_standby()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: standby\n");
|
|
#endif
|
|
|
|
stop_read();
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_stop()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: stop\n");
|
|
#endif
|
|
|
|
stop_read();
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_pause()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: pause\n");
|
|
#endif
|
|
|
|
stop_read();
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_init()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: init\n");
|
|
#endif
|
|
|
|
stop_read();
|
|
mode=0;
|
|
sr|=0x10;
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_mute()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: mute\n");
|
|
#endif
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_demute()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: demute\n");
|
|
#endif
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_setfilter()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: setfilter %08x,%08x\n",cmdbuf[0],cmdbuf[1]);
|
|
#endif
|
|
|
|
filter_file=cmdbuf[0];
|
|
filter_channel=cmdbuf[1];
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_setmode()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: setmode %08x\n",cmdbuf[0]);
|
|
#endif
|
|
|
|
mode=cmdbuf[0];
|
|
|
|
switch ((mode&mode_size_mask)>>mode_size_shift)
|
|
{
|
|
case 1:
|
|
secsize=2328;
|
|
secskip=24;
|
|
break;
|
|
|
|
case 2:
|
|
secsize=2340;
|
|
secskip=12;
|
|
break;
|
|
|
|
default:
|
|
secsize=2048;
|
|
secskip=24;
|
|
break;
|
|
}
|
|
|
|
send_result(intr_complete);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_getparam()
|
|
{
|
|
unsigned char data[6]=
|
|
{
|
|
status,
|
|
mode,
|
|
filter_file,
|
|
filter_channel,
|
|
0,
|
|
0
|
|
};
|
|
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: getparam [%02x %02x %02x %02x %02x %02x]\n",
|
|
data[0],
|
|
data[1],
|
|
data[2],
|
|
data[3],
|
|
data[4],
|
|
data[5]);
|
|
#endif
|
|
|
|
send_result(intr_complete,data,6);
|
|
}
|
|
|
|
#if 0
|
|
static void add_loc(unsigned char *dst, const unsigned char *src1, const unsigned char *src2)
|
|
{
|
|
int f=src1[2]+src2[2],
|
|
s=src1[1]+src2[1],
|
|
m=src1[0]+src2[0];
|
|
while (f>=75) { s++; f-=75; }
|
|
while (s>=60) { m++; s-=60; }
|
|
|
|
dst[0]=m;
|
|
dst[1]=s;
|
|
dst[2]=f;
|
|
}
|
|
#endif
|
|
static void sub_loc(unsigned char *dst, const unsigned char *src1, const unsigned char *src2)
|
|
{
|
|
int f=src1[2]-src2[2],
|
|
s=src1[1]-src2[1],
|
|
m=src1[0]-src2[0];
|
|
while (f<0) { s--; f+=75; }
|
|
while (s<0) { m--; s+=60; }
|
|
|
|
if (m<0)
|
|
m=s=f=0;
|
|
|
|
dst[0]=m;
|
|
dst[1]=s;
|
|
dst[2]=f;
|
|
}
|
|
|
|
void psxcd_device::cdcmd_getlocl()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: getlocl\n");
|
|
#endif
|
|
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: getlocl [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
|
|
lastsechdr[0],
|
|
lastsechdr[1],
|
|
lastsechdr[2],
|
|
lastsechdr[3],
|
|
lastsechdr[4],
|
|
lastsechdr[5],
|
|
lastsechdr[6],
|
|
lastsechdr[7]);
|
|
#endif
|
|
|
|
send_result(intr_complete,lastsechdr,8);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_getlocp()
|
|
{
|
|
unsigned char tloc[3],
|
|
twosec[3]={ 0,2,0 };
|
|
sub_loc(tloc,loc,twosec);
|
|
|
|
unsigned char data[8]=
|
|
{
|
|
0x01, // track
|
|
0x01, // index
|
|
decimal_to_bcd(tloc[0]), // min
|
|
decimal_to_bcd(tloc[1]), // sec
|
|
decimal_to_bcd(tloc[2]), // frame
|
|
decimal_to_bcd(loc[0]), // amin
|
|
decimal_to_bcd(loc[1]), // asec
|
|
decimal_to_bcd(loc[2]) // aframe
|
|
};
|
|
|
|
//unsigned char data[8]={ 2,1,0,0xff,0xff,0xff,0xff,0xff };
|
|
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: getlocp [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
|
|
data[0],
|
|
data[1],
|
|
data[2],
|
|
data[3],
|
|
data[4],
|
|
data[5],
|
|
data[6],
|
|
data[7]);
|
|
#endif
|
|
|
|
send_result(intr_complete,data,8);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_illegal()
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_gettn()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: gettn\n");
|
|
#endif
|
|
|
|
assert(driver);
|
|
|
|
unsigned char data[3]=
|
|
{
|
|
status,
|
|
decimal_to_bcd(driver->get_first_track()),
|
|
decimal_to_bcd(driver->get_num_tracks())
|
|
};
|
|
|
|
//stop_read();
|
|
send_result(intr_acknowledge,data,3);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_gettd()
|
|
{
|
|
unsigned char addr[3];
|
|
driver->get_track_address(bcd_to_decimal(cmdbuf[0]), addr);
|
|
|
|
unsigned char data[3]=
|
|
{
|
|
status,
|
|
decimal_to_bcd(addr[0]),
|
|
decimal_to_bcd(addr[1])
|
|
};
|
|
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: gettd %02x [%02x %02x %02x]\n",
|
|
cmdbuf[0],
|
|
data[0],
|
|
data[1],
|
|
data[2]);
|
|
#endif
|
|
|
|
//stop_read();
|
|
send_result(intr_acknowledge,data,3);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_seekl()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: seekl [%02d:%02d:%02d]\n",loc[0],loc[1],loc[2]);
|
|
#endif
|
|
|
|
curpos[0]=loc[0];
|
|
curpos[1]=loc[1];
|
|
curpos[2]=loc[2];
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_seekp()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: seekp\n");
|
|
#endif
|
|
|
|
curpos[0]=loc[0];
|
|
curpos[1]=loc[1];
|
|
curpos[2]=loc[2];
|
|
|
|
send_result(intr_acknowledge);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_test()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: test %08x\n",cmdbuf[0]);
|
|
#endif
|
|
|
|
static unsigned char data[4]=
|
|
{
|
|
0x95,
|
|
0x07,
|
|
0x06,
|
|
0xff
|
|
};
|
|
|
|
send_result(intr_complete,data,4);
|
|
}
|
|
|
|
void psxcd_device::cdcmd_id()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: id\n");
|
|
#endif
|
|
|
|
if (! open)
|
|
{
|
|
if (driver)
|
|
open=driver->read_toc();
|
|
}
|
|
|
|
if (open)
|
|
{
|
|
static unsigned char gamedata[8] = { 0x08, 0x00, 0x00, 0x00, 'S', 'C', 'E', 'A' };
|
|
static unsigned char audiodata[8] = { 0x08, 0x90, 0x00, 0x00, 'S', 'C', 'E', 'A' }; // drops into the audio CD player. 08 80 goes to the menu.
|
|
|
|
if (cdrom_get_track_type(m_cd, 0) == CD_TRACK_AUDIO)
|
|
{
|
|
send_result(intr_acknowledge,audiodata,8);
|
|
}
|
|
else
|
|
{
|
|
send_result(intr_acknowledge,gamedata,8);
|
|
}
|
|
} else
|
|
{
|
|
status=status_error|status_shellopen;
|
|
send_result(intr_diskerror);
|
|
}
|
|
}
|
|
|
|
void psxcd_device::cdcmd_reads()
|
|
{
|
|
curpos[0]=loc[0];
|
|
curpos[1]=loc[1];
|
|
curpos[2]=loc[2];
|
|
|
|
#ifdef skip_reads
|
|
#ifdef debug_cdrom
|
|
log("cdrom: reads [SKIPPING - RETURN COMPLETE]\n");
|
|
#endif
|
|
|
|
send_result(intr_complete);
|
|
#else
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: reads\n");
|
|
#endif
|
|
|
|
stop_read();
|
|
start_streaming();
|
|
#endif
|
|
}
|
|
|
|
void psxcd_device::cdcmd_reset()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: reset\n");
|
|
#endif
|
|
}
|
|
|
|
void psxcd_device::cdcmd_readtoc()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: readtoc\n");
|
|
#endif
|
|
|
|
static unsigned char data[4]=
|
|
{
|
|
0x00,
|
|
0x00,
|
|
0xff,
|
|
0xfe
|
|
};
|
|
|
|
send_result(intr_complete|0x10,data,2);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::cmd_complete(command_result *res)
|
|
{
|
|
bool doint=((res->res&0x10)==0);
|
|
#ifdef debug_cdrom
|
|
command_result *rf;
|
|
#endif
|
|
|
|
if (doint)
|
|
{
|
|
m_irq_handler(1);
|
|
}
|
|
|
|
add_result(res);
|
|
|
|
#ifdef debug_cdrom
|
|
if (doint)
|
|
{
|
|
printf("cdrom: irq [");
|
|
for (rf=res_queue; ((rf) && (rf->next)); rf=rf->next);
|
|
printf("%d ",rf->res);
|
|
printf("]\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::add_result(command_result *res)
|
|
{
|
|
command_result *rf;
|
|
|
|
if (res_queue)
|
|
{
|
|
for (rf=res_queue; rf->next; rf=rf->next);
|
|
rf->next=res;
|
|
} else
|
|
{
|
|
res_queue=res;
|
|
}
|
|
|
|
res->next=NULL;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
event *psxcd_device::send_result(const unsigned int res,
|
|
const unsigned char *data,
|
|
const unsigned int sz,
|
|
const unsigned int delay)
|
|
{
|
|
// Update shell open status
|
|
|
|
if (! open)
|
|
{
|
|
status=status_error|status_shellopen;
|
|
}
|
|
else
|
|
{
|
|
if (status&status_shellopen)
|
|
status=status_standby;
|
|
}
|
|
|
|
// Prepare event
|
|
|
|
event *ev=new event;
|
|
ev->t=delay;
|
|
ev->type=event_cmd_complete;
|
|
|
|
command_result *cr=(command_result *)ev->data;
|
|
|
|
cr->res=res;
|
|
if (sz)
|
|
{
|
|
assert(sz<sizeof(cr->data));
|
|
memcpy(cr->data,data,sz);
|
|
cr->sz=sz;
|
|
} else
|
|
{
|
|
cr->data[0]=status;
|
|
cr->sz=1;
|
|
}
|
|
|
|
// Avoid returning results after sector read results -
|
|
// delay the sector read slightly if necessary
|
|
|
|
UINT64 systime = machine().device<cpu_device>("maincpu")->total_cycles();
|
|
if ((next_read_event) && ((systime+ev->t)>(next_sector_t)))
|
|
{
|
|
UINT32 hz = m_sysclock / (delay + 2000);
|
|
next_read_event->timer->adjust(attotime::from_hz(hz), 0, attotime::never);
|
|
|
|
for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
|
|
{
|
|
if (m_eventfortimer[i] == next_read_event)
|
|
{
|
|
printf("Adjusting timer %d to %d hz]n", i, hz);
|
|
}
|
|
}
|
|
}
|
|
|
|
add_system_event(ev);
|
|
return ev;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::start_dma(UINT8 *mainram, UINT32 size)
|
|
{
|
|
if ((int)size>secleft)
|
|
{
|
|
printf("cdrom: dma past end of sector (secleft=%d sz=%d)\n",secleft,size);
|
|
}
|
|
|
|
// printf("cdrom: start dma %d bytes, %d remaining, secptr %p\n", size, secleft, secptr);
|
|
#ifdef debug_cdrom
|
|
if (size==12)
|
|
{
|
|
char poo[1024],*pp=poo;
|
|
for (unsigned int i=0; i<12; i++)
|
|
{
|
|
sprintf(pp,"%02x ",secptr[i]);
|
|
pp+=3;
|
|
}
|
|
printf("cdrom: data=%s\n",poo);
|
|
}
|
|
#endif
|
|
|
|
memcpy(mainram, secptr, size);
|
|
memset(secptr, 0xff, size);
|
|
|
|
secptr += size;
|
|
secleft -= size;
|
|
|
|
if (secleft<0) secleft=0;
|
|
if (secleft==0) sr&=~0x40;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::prefetch_next_sector()
|
|
{
|
|
unsigned int pos=msf_to_sector(curpos);
|
|
assert(driver);
|
|
driver->prefetch_sector(pos);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
bool psxcd_device::read_next_sector(const bool block)
|
|
{
|
|
unsigned int pos=msf_to_sector(curpos);
|
|
unsigned char *buf=&secbuf[sechead*raw_sector_size];
|
|
assert(driver);
|
|
assert(secin<sector_buffer_size);
|
|
|
|
// printf("read_next_sector: sec %d, sechead %d, raw_sector_size %d\n", pos, sechead, raw_sector_size);
|
|
if (driver->read_sector(pos, buf, block))
|
|
{
|
|
// printf("buf contents = %02x %02x | %02x %02x\n", buf[0], buf[1], buf[0x20], buf[0x21]);
|
|
|
|
sechead=(sechead+1)&(sector_buffer_size-1);
|
|
secin++;
|
|
|
|
memcpy(lastsechdr,&secbuf[raw_sector_size*sectail]+12,8);
|
|
|
|
return true;
|
|
} else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::read_sector()
|
|
{
|
|
next_read_event=NULL;
|
|
|
|
if (status & status_reading)
|
|
{
|
|
bool isend=false;
|
|
|
|
if (read_next_sector(false))
|
|
{
|
|
unsigned char *rawsec;
|
|
|
|
if ((mode&mode_adpcm) && (streaming))
|
|
{
|
|
rawsec=&secbuf[raw_sector_size*sectail];
|
|
secptr=rawsec+24;
|
|
secleft=2048;
|
|
}
|
|
else
|
|
{
|
|
rawsec=&secbuf[raw_sector_size*sectail];
|
|
secptr=rawsec+secskip;
|
|
secleft=secsize;
|
|
}
|
|
|
|
secin--;
|
|
sectail=(sectail+1)&(sector_buffer_size-1);
|
|
|
|
//
|
|
|
|
bool isxa=false;
|
|
|
|
subheader *sub=(subheader *)(rawsec+16);
|
|
|
|
#ifdef dump_subheader
|
|
printf("cdrom: subheader file=%02x chan=%02x submode=%02x coding=%02x [%02x%02x%02x%02x]\n",
|
|
sub->file,
|
|
sub->channel,
|
|
sub->submode,
|
|
sub->coding,
|
|
rawsec[0xc],
|
|
rawsec[0xd],
|
|
rawsec[0xe],
|
|
rawsec[0xf]);
|
|
#endif
|
|
|
|
status&=~status_playing;
|
|
isxa=((mode&mode_adpcm) && (sub->submode&submode_audio));
|
|
|
|
if (((mode&mode_channel)==0) ||
|
|
((sub->file==filter_file) && (sub->channel==filter_channel)))
|
|
{
|
|
if (isxa)
|
|
{
|
|
if (sub->submode&submode_eof)
|
|
{
|
|
isend=true;
|
|
//printf("end of file\n");
|
|
}
|
|
|
|
#ifndef disable_xa_prefetch
|
|
unsigned int cursec=msf_to_sector(curpos);
|
|
|
|
if (xa_prefetch_sector==-1)
|
|
{
|
|
xa_prefetch_sector=cursec;
|
|
machine().device<spu_device>("spu")->flush_xa();
|
|
}
|
|
|
|
unsigned char *xaptr;
|
|
unsigned int xasecsz;
|
|
|
|
while (1)
|
|
{
|
|
int dist=xa_prefetch_sector-cursec;
|
|
if (dist>max_xa_prefetch_distance) break;
|
|
|
|
xaptr=driver->get_prefetch_sector(xa_prefetch_sector,&xasecsz);
|
|
if (! xaptr) break;
|
|
|
|
switch (xasecsz)
|
|
{
|
|
case 2336:
|
|
break;
|
|
|
|
default:
|
|
xaptr+=16;
|
|
break;
|
|
}
|
|
|
|
subheader *xasub=(subheader *)xaptr;
|
|
|
|
if ((xasub->submode&submode_audio) &&
|
|
(((mode&mode_channel)==0) ||
|
|
((xasub->file==sub->file) &&
|
|
(xasub->channel==sub->channel))))
|
|
{
|
|
if (! machine().device<spu_device>("spu")->play_xa(xa_prefetch_sector,xaptr))
|
|
break;
|
|
}
|
|
xa_prefetch_sector++;
|
|
}
|
|
#else
|
|
machine().device<spu_device>("spu")->play_xa(0,rawsec+16);
|
|
#endif
|
|
|
|
status|=status_playing;
|
|
}
|
|
}
|
|
|
|
if ((mode&mode_autopause)==0)
|
|
isend=false;
|
|
|
|
//
|
|
|
|
curpos[2]++;
|
|
if (curpos[2]==75)
|
|
{
|
|
curpos[2]=0;
|
|
curpos[1]++;
|
|
if (curpos[1]==60)
|
|
{
|
|
curpos[1]=0;
|
|
curpos[0]++;
|
|
}
|
|
}
|
|
|
|
loc[0]=curpos[0];
|
|
loc[1]=curpos[1];
|
|
loc[2]=curpos[2];
|
|
|
|
//
|
|
|
|
command_result *res=new command_result;
|
|
res->res=isend?intr_dataend:intr_dataready;
|
|
res->data[0]=status;
|
|
res->sz=1;
|
|
|
|
sr|=0x40;
|
|
|
|
if ((streaming) && (isxa))
|
|
{
|
|
global_free(res);
|
|
res=NULL;
|
|
}
|
|
|
|
if (res)
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom:: data ready\n");
|
|
#endif
|
|
|
|
cmd_complete(res);
|
|
}
|
|
}
|
|
|
|
if (! isend)
|
|
{
|
|
unsigned int cyc=read_sector_cycles;
|
|
if (mode&mode_double_speed) cyc>>=1;
|
|
|
|
next_sector_t+=cyc;
|
|
|
|
event *ev=new event;
|
|
ev->t=cyc;
|
|
ev->type=event_read_sector;
|
|
next_read_event=ev;
|
|
add_system_event(ev);
|
|
|
|
//read_next_sector();
|
|
} else
|
|
{
|
|
printf("autopause xa\n");
|
|
stop_read();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
bool psxcd_device::play_cdda_sector(const unsigned int sector,
|
|
unsigned char *rawsec)
|
|
{
|
|
bool isdata=true;
|
|
|
|
if (rawsec[0]!=0)
|
|
{
|
|
isdata=false;
|
|
} else
|
|
{
|
|
for (int i=0; i<10; i++)
|
|
if (rawsec[i+1]!=0xff)
|
|
{
|
|
isdata=false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (! isdata)
|
|
{
|
|
return machine().device<spu_device>("spu")->play_cdda(sector,rawsec);
|
|
} else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::play_sector()
|
|
{
|
|
next_read_event=NULL;
|
|
|
|
if (status&status_playing)
|
|
{
|
|
#ifdef disable_cdda_prefetch
|
|
unsigned char *rawsec=&secbuf[raw_sector_size*sectail];
|
|
#endif
|
|
secin--;
|
|
sectail=(sectail+1)&(sector_buffer_size-1);
|
|
|
|
//
|
|
|
|
#ifndef disable_cdda_prefetch
|
|
unsigned int cursec=msf_to_sector(curpos);
|
|
|
|
if (cdda_prefetch_sector==-1)
|
|
{
|
|
cdda_prefetch_sector=cursec;
|
|
machine().device<spu_device>("spu")->flush_cdda();
|
|
}
|
|
|
|
unsigned char *cddaptr;
|
|
// bool full=false;
|
|
unsigned int cddasecsz;
|
|
|
|
while (1)
|
|
{
|
|
int dist=cdda_prefetch_sector-cursec;
|
|
if (dist>max_cdda_prefetch_distance) break;
|
|
|
|
cddaptr=driver->get_prefetch_sector(cdda_prefetch_sector,&cddasecsz);
|
|
if (! cddaptr) break;
|
|
|
|
if (! play_cdda_sector(cdda_prefetch_sector,cddaptr))
|
|
break;
|
|
|
|
cdda_prefetch_sector++;
|
|
}
|
|
#else
|
|
play_cdda_sector(0,rawsec);
|
|
#endif
|
|
|
|
//
|
|
|
|
curpos[2]++;
|
|
if (curpos[2]==75)
|
|
{
|
|
curpos[2]=0;
|
|
curpos[1]++;
|
|
if (curpos[1]==60)
|
|
{
|
|
curpos[1]=0;
|
|
curpos[0]++;
|
|
}
|
|
}
|
|
|
|
loc[0]=curpos[0];
|
|
loc[1]=curpos[1];
|
|
loc[2]=curpos[2];
|
|
|
|
//
|
|
|
|
if (mode&mode_autopause)
|
|
{
|
|
if (msf_to_sector(loc)>=autopause_sector)
|
|
{
|
|
printf("autopause cdda\n");
|
|
|
|
command_result *res=new command_result;
|
|
res->res=intr_dataend;
|
|
res->data[0]=status_standby;
|
|
res->sz=1;
|
|
cmd_complete(res);
|
|
stop_read();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (mode&mode_report)
|
|
{
|
|
command_result *res=new command_result;
|
|
res->res=intr_complete; //dataready;
|
|
|
|
res->data[0]=status_playing|status_standby;
|
|
res->data[1]=0x01;
|
|
res->data[2]=0x80;
|
|
res->data[3]=decimal_to_bcd(loc[0]);
|
|
res->data[4]=decimal_to_bcd(loc[1])|0x80;
|
|
res->data[5]=decimal_to_bcd(loc[2]);
|
|
|
|
res->sz=8;
|
|
|
|
cmd_complete(res);
|
|
}
|
|
|
|
unsigned int cyc=read_sector_cycles;
|
|
|
|
event *ev=new event;
|
|
ev->t=next_sector_t - machine().device<cpu_device>("maincpu")->total_cycles();
|
|
ev->type=event_play_sector;
|
|
|
|
next_sector_t+=cyc;
|
|
|
|
next_read_event=ev;
|
|
add_system_event(ev);
|
|
|
|
read_next_sector();
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::preread_sector()
|
|
{
|
|
next_read_event=NULL;
|
|
|
|
//
|
|
|
|
event *ev=new event;
|
|
|
|
unsigned int pos=msf_to_sector(curpos);
|
|
unsigned char *buf=&secbuf[sechead*raw_sector_size];
|
|
if (! driver->read_sector(pos,buf,false))
|
|
{
|
|
ev->t=(m_sysclock/60);
|
|
ev->type=event_preread_sector;
|
|
|
|
unsigned int cyc=read_sector_cycles;
|
|
if (mode&mode_double_speed) cyc>>=1;
|
|
next_sector_t=ev->t+(cyc-preread_delay)+machine().device<cpu_device>("maincpu")->total_cycles();
|
|
} else
|
|
{
|
|
memcpy(lastsechdr,buf+12,8);
|
|
|
|
//
|
|
|
|
command_result *res=new command_result;
|
|
res->res=intr_complete;
|
|
res->data[0]=status;
|
|
res->sz=1;
|
|
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: read acknowledge\n");
|
|
#endif
|
|
|
|
cmd_complete(res);
|
|
|
|
//
|
|
|
|
ev->t=next_sector_t - machine().device<cpu_device>("maincpu")->total_cycles();
|
|
ev->type=event_read_sector;
|
|
|
|
//read_next_sector();
|
|
}
|
|
|
|
next_read_event=ev;
|
|
add_system_event(ev);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::start_read()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: start read\n");
|
|
#endif
|
|
|
|
assert((status&(status_reading|status_playing))==0);
|
|
|
|
status|=status_reading;
|
|
|
|
secin=sechead=sectail=0;
|
|
xa_prefetch_sector=-1;
|
|
|
|
unsigned int cyc=read_sector_cycles;
|
|
if (mode&mode_double_speed) cyc>>=1;
|
|
|
|
INT64 systime=machine().device<cpu_device>("maincpu")->total_cycles();
|
|
|
|
systime+=start_read_delay;
|
|
|
|
event *ev=new event;
|
|
ev->t=start_read_delay+preread_delay;
|
|
ev->type=event_preread_sector;
|
|
|
|
next_sector_t=systime+cyc;
|
|
next_read_event=ev;
|
|
add_system_event(ev);
|
|
|
|
prefetch_next_sector();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::start_streaming()
|
|
{
|
|
assert(! streaming);
|
|
|
|
streaming=true;
|
|
start_read();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::start_play()
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom: start play\n");
|
|
#endif
|
|
|
|
status|=status_playing;
|
|
|
|
secin=sechead=sectail=0;
|
|
cdda_prefetch_sector=-1;
|
|
|
|
if (mode&mode_autopause)
|
|
{
|
|
unsigned int pos=msf_to_sector(curpos);
|
|
driver->find_track(pos+150,NULL,&autopause_sector);
|
|
// printf("pos=%d auto=%d\n",pos,autopause_sector);
|
|
}
|
|
|
|
unsigned int cyc=read_sector_cycles;
|
|
|
|
next_sector_t=machine().device<cpu_device>("maincpu")->total_cycles()+cyc;
|
|
|
|
event *ev=new event;
|
|
ev->t=next_sector_t - machine().device<cpu_device>("maincpu")->total_cycles();
|
|
ev->type=event_play_sector;
|
|
|
|
next_sector_t+=cyc;
|
|
|
|
next_read_event=ev;
|
|
add_system_event(ev);
|
|
|
|
read_next_sector();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::stop_read()
|
|
{
|
|
#ifdef debug_cdrom
|
|
if (status&status_reading)
|
|
printf("cdrom: stop read\n");
|
|
#endif
|
|
status&=~(status_reading|status_playing);
|
|
streaming=false;
|
|
|
|
if (next_read_event)
|
|
{
|
|
next_read_event->timer->adjust(attotime::never, 0, attotime::never);
|
|
for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
|
|
{
|
|
if (m_timers[i] == next_read_event->timer)
|
|
{
|
|
m_timerinuse[i] = false;
|
|
m_eventfortimer[i] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
global_free(next_read_event);
|
|
next_read_event=NULL;
|
|
}
|
|
|
|
unsigned int sector=msf_to_sector(curpos);
|
|
machine().device<spu_device>("spu")->flush_xa(sector);
|
|
machine().device<spu_device>("spu")->flush_cdda(sector);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
void psxcd_device::set_driver(cdrom_driver *d)
|
|
{
|
|
char err[1024];
|
|
|
|
if (d)
|
|
{
|
|
if (d->is_usable(err,1024))
|
|
{
|
|
driver=d;
|
|
open=false;
|
|
|
|
if (! first_open)
|
|
{
|
|
command_result *res=new command_result;
|
|
res->res=intr_acknowledge;
|
|
res->data[0]=status_standby;
|
|
res->sz=1;
|
|
|
|
cmd_complete(res);
|
|
|
|
open_nops=10;
|
|
}
|
|
|
|
first_open=false;
|
|
}
|
|
} else
|
|
{
|
|
driver=NULL;
|
|
open=false;
|
|
|
|
command_result *res=new command_result;
|
|
res->res=intr_acknowledge;
|
|
res->data[0]=status_shellopen;
|
|
res->sz=1;
|
|
|
|
cmd_complete(res);
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void psxcd_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
|
|
{
|
|
event *ev = m_eventfortimer[tid];
|
|
|
|
// printf("timer %d fired, performing event type %d\n", tid, ev->type);
|
|
|
|
switch (ev->type)
|
|
{
|
|
case event_cmd_complete:
|
|
{
|
|
#ifdef debug_cdrom
|
|
printf("cdrom:: event cmd complete\n");
|
|
#endif
|
|
|
|
command_result *res=new command_result;
|
|
memcpy(res,ev->data,sizeof(command_result));
|
|
cmd_complete(res);
|
|
break;
|
|
}
|
|
|
|
case event_preread_sector:
|
|
preread_sector();
|
|
break;
|
|
|
|
case event_read_sector:
|
|
read_sector();
|
|
break;
|
|
|
|
case event_play_sector:
|
|
play_sector();
|
|
break;
|
|
}
|
|
|
|
// free the timer
|
|
// printf("Freeing timer %d\n", tid);
|
|
m_timers[tid]->adjust(attotime::never, 0, attotime::never);
|
|
m_timerinuse[tid] = false;
|
|
m_eventfortimer[tid] = NULL;
|
|
|
|
global_free(ev);
|
|
}
|
|
|
|
void psxcd_device::add_system_event(event *ev)
|
|
{
|
|
emu_timer *timer = NULL;
|
|
int tnum = -1;
|
|
|
|
// allocate a timer for this event
|
|
for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
|
|
{
|
|
if (!m_timerinuse[i])
|
|
{
|
|
tnum = i;
|
|
timer = m_timers[i];
|
|
m_timerinuse[i] = true;
|
|
m_eventfortimer[i] = ev;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tnum == -1)
|
|
{
|
|
fatalerror("PSXCD: ran out of timers!\n");
|
|
}
|
|
|
|
// ev->t is in maincpu clock cycles
|
|
UINT32 hz = m_sysclock / ev->t;
|
|
// printf("add_system_event: event type %d for %d hz (using timer %d)\n", ev->type, hz, tnum);
|
|
timer->adjust(attotime::from_hz(hz), tnum, attotime::never);
|
|
|
|
// back-reference the timer from the event
|
|
ev->timer = timer;
|
|
}
|
|
|