Port from MESS, nw

This commit is contained in:
Angelo Salese 2011-06-30 13:43:46 +00:00
parent 5257d55866
commit d05d998ea5
6 changed files with 816 additions and 794 deletions

2
.gitattributes vendored
View File

@ -3929,6 +3929,8 @@ src/mame/machine/simpsons.c svneol=native#text/plain
src/mame/machine/slapfght.c svneol=native#text/plain
src/mame/machine/slapstic.c svneol=native#text/plain
src/mame/machine/slikshot.c svneol=native#text/plain
src/mame/machine/smpc.c svneol=native#text/plain
src/mame/machine/smpc.h svneol=native#text/plain
src/mame/machine/snes.c svneol=native#text/plain
src/mame/machine/snes7110.c svneol=native#text/plain
src/mame/machine/snesbsx.c svneol=native#text/plain

View File

@ -106,6 +106,7 @@ also has a DSP;
#include "sound/scsp.h"
#include "sound/cdda.h"
#include "machine/stvprot.h"
#include "machine/smpc.h"
#include "includes/stv.h"
#include "imagedev/chd_cd.h"
#include "imagedev/cartslot.h"
@ -114,11 +115,27 @@ also has a DSP;
/* TODO: do this in a verboselog style */
#define LOG_CDB 0
#define LOG_SMPC 0
#define LOG_SCU 0
#define LOG_IRQ 0
#define LOG_IOGA 0
static int DectoBCD(int num)
{
int i, cnt = 0, tmp, res = 0;
while (num > 0) {
tmp = num;
while (tmp >= 10) tmp %= 10;
for (i=0; i<cnt; i++)
tmp *= 16;
res += tmp;
cnt++;
num /= 10;
}
return res;
}
/**************************************************************************************/
/*to be added into a stv Header file,remember to remove all the static...*/
@ -129,24 +146,6 @@ also has a DSP;
/*SMPC stuff*/
/*SCU stuff*/
static struct
{
UINT8 vblank_out;
UINT8 vblank_in;
UINT8 hblank_in;
UINT8 timer_0;
UINT8 timer_1;
UINT8 dsp_end;
UINT8 sound_req;
UINT8 smpc;
UINT8 pad;
UINT8 dma_end[3];
UINT8 dma_ill;
UINT8 vdp1_end;
UINT8 abus;
}stv_irq;
static void scu_do_transfer(running_machine &machine,UINT8 event);
static void scu_dma_direct(address_space *space, UINT8 dma_ch); /*DMA level 0 direct transfer function*/
static void scu_dma_indirect(address_space *space, UINT8 dma_ch); /*DMA level 0 indirect transfer function*/
@ -182,722 +181,6 @@ if(state->m_scu_regs[42] & 1)//IRQ ACK
/**************************************************************************************/
static int DectoBCD(int num)
{
int i, cnt = 0, tmp, res = 0;
while (num > 0) {
tmp = num;
while (tmp >= 10) tmp %= 10;
for (i=0; i<cnt; i++)
tmp *= 16;
res += tmp;
cnt++;
num /= 10;
}
return res;
}
/* SMPC
System Manager and Peripheral Control
*/
/* SMPC Addresses
00
01 -w Input Register 0 (IREG)
02
03 -w Input Register 1
04
05 -w Input Register 2
06
07 -w Input Register 3
08
09 -w Input Register 4
0a
0b -w Input Register 5
0c
0d -w Input Register 6
0e
0f
10
11
12
13
14
15
16
17
18
19
1a
1b
1c
1d
1e
1f -w Command Register (COMREG)
20
21 r- Output Register 0 (OREG)
22
23 r- Output Register 1
24
25 r- Output Register 2
26
27 r- Output Register 3
28
29 r- Output Register 4
2a
2b r- Output Register 5
2c
2d r- Output Register 6
2e
2f r- Output Register 7
30
31 r- Output Register 8
32
33 r- Output Register 9
34
35 r- Output Register 10
36
37 r- Output Register 11
38
39 r- Output Register 12
3a
3b r- Output Register 13
3c
3d r- Output Register 14
3e
3f r- Output Register 15
40
41 r- Output Register 16
42
43 r- Output Register 17
44
45 r- Output Register 18
46
47 r- Output Register 19
48
49 r- Output Register 20
4a
4b r- Output Register 21
4c
4d r- Output Register 22
4e
4f r- Output Register 23
50
51 r- Output Register 24
52
53 r- Output Register 25
54
55 r- Output Register 26
56
57 r- Output Register 27
58
59 r- Output Register 28
5a
5b r- Output Register 29
5c
5d r- Output Register 30
5e
5f r- Output Register 31
60
61 r- SR
62
63 rw SF
64
65
66
67
68
69
6a
6b
6c
6d
6e
6f
70
71
72
73
74
75 rw PDR1
76
77 rw PDR2
78
79 -w DDR1
7a
7b -w DDR2
7c
7d -w IOSEL2/1
7e
7f -w EXLE2/1
*/
static READ8_HANDLER( stv_SMPC_r8 )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
int return_data;
return_data = state->m_smpc_ram[offset];
if (offset == 0x61) // ?? many games need this or the controls don't work
return_data = 0x20 ^ 0xff;
if (offset == 0x75)//PDR1 read
return_data = input_port_read(space->machine(), "DSW1");
if (offset == 0x77)//PDR2 read
return_data= (0xfe | space->machine().device<eeprom_device>("eeprom")->read_bit());
// if (offset == 0x33) //country code
// return_data = input_port_read(machine, "FAKE");
//if(LOG_SMPC) logerror ("cpu %s (PC=%08X) SMPC: Read from Byte Offset %02x Returns %02x\n", space->device().tag(), cpu_get_pc(&space->device()), offset, return_data);
return return_data;
}
static TIMER_CALLBACK( stv_bankswitch_state )
{
saturn_state *state = machine.driver_data<saturn_state>();
static const char *const banknames[] = { "game0", "game1", "game2", "game3" };
UINT8* game_region;
if(state->m_prev_bankswitch != param)
{
game_region = machine.region(banknames[param])->base();
if (game_region)
memcpy(machine.region("abus")->base(), game_region, 0x3000000);
else
memset(machine.region("abus")->base(), 0x00, 0x3000000);
state->m_prev_bankswitch = param;
}
}
static void stv_select_game(running_machine &machine, int gameno)
{
machine.scheduler().timer_set(attotime::zero, FUNC(stv_bankswitch_state), gameno);
}
static void smpc_master_on(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
device_set_input_line(state->m_maincpu, INPUT_LINE_RESET, CLEAR_LINE);
}
static void smpc_slave_enable(running_machine &machine,UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
device_set_input_line(state->m_slave, INPUT_LINE_RESET, cmd ? ASSERT_LINE : CLEAR_LINE);
}
static void smpc_sound_enable(running_machine &machine,UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
device_set_input_line(state->m_audiocpu, INPUT_LINE_RESET, cmd ? ASSERT_LINE : CLEAR_LINE);
state->m_en_68k = cmd ^ 1;
}
static void smpc_system_reset(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
/*Only backup ram and SMPC ram are retained after that this command is issued.*/
memset(state->m_scu_regs ,0x00,0x000100);
memset(state->m_scsp_regs,0x00,0x001000);
memset(state->m_sound_ram,0x00,0x080000);
memset(state->m_workram_h,0x00,0x100000);
memset(state->m_workram_l,0x00,0x100000);
memset(state->m_vdp2_regs,0x00,0x040000);
memset(state->m_vdp2_vram,0x00,0x100000);
memset(state->m_vdp2_cram,0x00,0x080000);
memset(state->m_vdp1_vram,0x00,0x100000);
//A-Bus
device_set_input_line(state->m_maincpu, INPUT_LINE_RESET, PULSE_LINE);
}
static void smpc_change_clock(running_machine &machine, UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
UINT32 xtal;
xtal = cmd ? MASTER_CLOCK_320 : MASTER_CLOCK_352;
machine.device("maincpu")->set_unscaled_clock(xtal/2);
machine.device("slave")->set_unscaled_clock(xtal/2);
state->m_vdp2.dotsel = cmd ^ 1;
stv_vdp2_dynamic_res_change(machine);
device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, PULSE_LINE); // ff said this causes nmi, should we set a timer then nmi?
smpc_slave_enable(machine,1);
/* TODO: VDP1 / VDP2 / SCU / SCSP default power ON values */
}
static void smpc_intbackhelper(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
int pad,i;
static const char *const padnames[] = { "JOY1", "JOY2" };
if (state->m_smpc.intback_stage == 1)
{
state->m_smpc.intback_stage++;
return;
}
// if (LOG_SMPC) logerror("SMPC: providing PAD data for intback, pad %d\n", intback_stage-2);
for(i=0;i<2;i++)
{
pad = input_port_read(machine, padnames[i]);
state->m_smpc_ram[0x21+i*8] = 0xf1; // no tap, direct connect
state->m_smpc_ram[0x23+i*8] = 0x02; // saturn pad
state->m_smpc_ram[0x25+i*8] = pad>>8;
state->m_smpc_ram[0x27+i*8] = pad & 0xff;
}
if (state->m_smpc.intback_stage == 3)
{
state->m_smpc.smpcSR = (0x80 | state->m_smpc.pmode); // pad 2, no more data, echo back pad mode set by intback
}
else
{
state->m_smpc.smpcSR = (0xe0 | state->m_smpc.pmode); // pad 1, more data, echo back pad mode set by intback
}
state->m_smpc.intback_stage++;
}
/* sys_type 1 == STV, 0 == SATURN */
static TIMER_CALLBACK( smpc_intback )
{
saturn_state *state = machine.driver_data<saturn_state>();
system_time systime;
machine.base_datetime(systime);
UINT8 sys_type = param;
state->m_smpc_ram[0x21] = (0x80) | ((state->m_NMI_reset & 1) << 6);
if(sys_type == 0)
{
state->m_smpc_ram[0x23] = dec_2_bcd(systime.local_time.year / 100);
state->m_smpc_ram[0x25] = dec_2_bcd(systime.local_time.year % 100);
state->m_smpc_ram[0x27] = (systime.local_time.weekday << 4) | (systime.local_time.month + 1);
state->m_smpc_ram[0x29] = dec_2_bcd(systime.local_time.mday);
state->m_smpc_ram[0x2b] = dec_2_bcd(systime.local_time.hour);
state->m_smpc_ram[0x2d] = dec_2_bcd(systime.local_time.minute);
state->m_smpc_ram[0x2f] = dec_2_bcd(systime.local_time.second);
}
state->m_smpc_ram[0x31]=0x00; //?
//state->m_smpc_ram[0x33]=input_port_read(space->machine(), "FAKE");
state->m_smpc_ram[0x35]= 0 << 7 |
state->m_vdp2.dotsel << 6 |
1 << 5 |
1 << 4 |
0 << 3 | //MSHNMI
1 << 2 |
0 << 1 | //SYSRES
0 << 0; //SOUNDRES
state->m_smpc_ram[0x37]= 0 << 6; //CDRES
state->m_smpc_ram[0x39]=sys_type ? 0xff : state->m_smpc.SMEM[0];
state->m_smpc_ram[0x3b]=sys_type ? 0xff : state->m_smpc.SMEM[1];
state->m_smpc_ram[0x3d]=sys_type ? 0xff : state->m_smpc.SMEM[2];
state->m_smpc_ram[0x3f]=sys_type ? 0xff : state->m_smpc.SMEM[3];
state->m_smpc_ram[0x41]=0xff;
state->m_smpc_ram[0x43]=0xff;
state->m_smpc_ram[0x45]=0xff;
state->m_smpc_ram[0x47]=0xff;
state->m_smpc_ram[0x49]=0xff;
state->m_smpc_ram[0x4b]=0xff;
state->m_smpc_ram[0x4d]=0xff;
state->m_smpc_ram[0x4f]=0xff;
state->m_smpc_ram[0x51]=0xff;
state->m_smpc_ram[0x53]=0xff;
state->m_smpc_ram[0x55]=0xff;
state->m_smpc_ram[0x57]=0xff;
state->m_smpc_ram[0x59]=0xff;
state->m_smpc_ram[0x5b]=0xff;
state->m_smpc_ram[0x5d]=0xff;
if(sys_type == 0)
{
state->m_smpc.smpcSR = 0x60; // peripheral data ready, no reset, etc.
state->m_smpc.pmode = state->m_smpc_ram[1]>>4;
state->m_smpc.intback_stage = 2;
smpc_intbackhelper(machine);
}
// /*This is for RTC,cartridge code and similar stuff...*/
//if(LOG_SMPC) logerror ("Interrupt: System Manager (SMPC) at scanline %04x, Vector 0x47 Level 0x08\n",scanline);
if(stv_irq.smpc)
device_set_input_line_and_vector(state->m_maincpu, 8, HOLD_LINE, 0x47);
}
static void smpc_rtc_write(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
state->m_smpc_ram[0x2f] = state->m_smpc_ram[0x0d];
state->m_smpc_ram[0x2d] = state->m_smpc_ram[0x0b];
state->m_smpc_ram[0x2b] = state->m_smpc_ram[0x09];
state->m_smpc_ram[0x29] = state->m_smpc_ram[0x07];
state->m_smpc_ram[0x27] = state->m_smpc_ram[0x05];
state->m_smpc_ram[0x25] = state->m_smpc_ram[0x03];
state->m_smpc_ram[0x23] = state->m_smpc_ram[0x01];
}
static void smpc_memory_setting(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
state->m_smpc.SMEM[0] = state->m_smpc_ram[1];
state->m_smpc.SMEM[1] = state->m_smpc_ram[3];
state->m_smpc.SMEM[2] = state->m_smpc_ram[5];
state->m_smpc.SMEM[3] = state->m_smpc_ram[7];
}
static void smpc_nmi_req(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
/*NMI is unconditionally requested?*/
device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, PULSE_LINE);
}
static void smpc_nmi_set(running_machine &machine,UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
state->m_NMI_reset = cmd ^ 1;
state->m_smpc_ram[0x21] = (0x80) | ((state->m_NMI_reset & 1) << 6);
}
static WRITE8_HANDLER( stv_SMPC_w8 )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
system_time systime;
space->machine().base_datetime(systime);
// if(LOG_SMPC) logerror ("8-bit SMPC Write to Offset %02x with Data %02x\n", offset, data);
state->m_smpc_ram[offset] = data;
if(offset == 0x75)
{
/*
-xx- ---- PDR1
---x ---- EEPROM write bit
---- x--- EEPROM CLOCK line
---- -x-- EEPROM CS line
---- --xx A-Bus bank bits
*/
eeprom_device *eeprom = space->machine().device<eeprom_device>("eeprom");
eeprom->set_clock_line((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
eeprom->write_bit(data & 0x10);
eeprom->set_cs_line((data & 0x04) ? CLEAR_LINE : ASSERT_LINE);
state->m_stv_multi_bank = data & 3;
stv_select_game(space->machine(), state->m_stv_multi_bank);
state->m_smpc.PDR1 = (data & 0x60);
}
if(offset == 0x77)
{
/*
-xx- ---- PDR2
---x ---- Enable Sound System (ACTIVE LOW)
*/
//popmessage("PDR2 = %02x",state->m_smpc_ram[0x77]);
if(LOG_SMPC) logerror("SMPC: M68k %s\n",(state->m_smpc_ram[0x77] & 0x10) ? "off" : "on");
cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_RESET, (state->m_smpc_ram[0x77] & 0x10) ? ASSERT_LINE : CLEAR_LINE);
state->m_en_68k = ((state->m_smpc_ram[0x77] & 0x10) >> 4) ^ 1;
//if(LOG_SMPC) logerror("SMPC: ram [0x77] = %02x\n",state->m_smpc_ram[0x77]);
state->m_smpc.PDR2 = (data & 0x60);
}
if(offset == 0x7d)
{
/*
---- --x- IOSEL2 direct (1) / control mode (0) port select
---- ---x IOSEL1 direct (1) / control mode (0) port select
*/
state->m_smpc.IOSEL1 = (state->m_smpc_ram[0x7d] & 1) >> 0;
state->m_smpc.IOSEL2 = (state->m_smpc_ram[0x7d] & 2) >> 1;
}
if(offset == 0x7f)
{
//enable PAD irq & VDP2 external latch for port 1/2
state->m_smpc.EXLE1 = (state->m_smpc_ram[0x7f] & 1) >> 0;
state->m_smpc.EXLE2 = (state->m_smpc_ram[0x7f] & 2) >> 1;
if(state->m_smpc.EXLE1 || state->m_smpc.EXLE2)
{
//if(LOG_SMPC) logerror ("Interrupt: PAD irq at scanline %04x, Vector 0x48 Level 0x08\n",scanline);
//cputag_set_input_line_and_vector(space->machine(), "maincpu", 8, (stv_irq.pad) ? HOLD_LINE : CLEAR_LINE, 0x48);
}
}
if (offset == 0x1f) // COMREG
{
switch (data)
{
case 0x00:
if(LOG_SMPC) logerror ("SMPC: Master ON\n");
smpc_master_on(space->machine());
break;
//in theory 0x01 is for Master OFF,but obviously is not used.
case 0x02:
case 0x03:
if(LOG_SMPC) logerror ("SMPC: Slave %s\n",(data & 1) ? "off" : "on");
smpc_slave_enable(space->machine(),(data & 1));
break;
case 0x06:
case 0x07:
if(LOG_SMPC) logerror ("SMPC: Sound %s, ignored\n",(data & 1) ? "off" : "on");
break;
/*CD (SH-1) ON/OFF,guess that this is needed for Sports Fishing games...*/
//case 0x08:
//case 0x09:
case 0x0d:
if(LOG_SMPC) logerror ("SMPC: System Reset\n");
smpc_system_reset(space->machine());
break;
case 0x0e:
case 0x0f:
if(LOG_SMPC) logerror ("SMPC: Change Clock to %s\n",data & 1 ? "320" : "352");
smpc_change_clock(space->machine(),data & 1);
break;
/*"Interrupt Back"*/
case 0x10:
if(LOG_SMPC) logerror ("SMPC: Status Acquire\n");
space->machine().scheduler().timer_set(attotime::from_msec(16), FUNC(smpc_intback),1); //TODO: variable time
break;
/* RTC write*/
case 0x16:
if(LOG_SMPC) logerror("SMPC: RTC write\n");
smpc_rtc_write(space->machine());
break;
/* SMPC memory setting*/
case 0x17:
if(LOG_SMPC) logerror ("SMPC: memory setting\n");
//smpc_memory_setting(space->machine());
break;
case 0x18:
if(LOG_SMPC) logerror ("SMPC: NMI request\n");
smpc_nmi_req(space->machine());
break;
case 0x19:
case 0x1a:
if(LOG_SMPC) logerror ("SMPC: NMI %sable\n",data & 1 ? "Dis" : "En");
smpc_nmi_set(space->machine(),data & 1);
break;
default:
printf ("cpu '%s' (PC=%08X) SMPC: undocumented Command %02x\n", space->device().tag(), cpu_get_pc(&space->device()), data);
}
// we've processed the command, clear status flag
state->m_smpc_ram[0x5f] = data; //read-back command
state->m_smpc_ram[0x63] = 0x00;
/*TODO:emulate the timing of each command...*/
}
}
static READ8_HANDLER( saturn_SMPC_r8 )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
int return_data;
return_data = state->m_smpc_ram[offset];
if ((offset == 0x61))
return_data = state->m_smpc.smpcSR;
if (offset == 0x75 || offset == 0x77)//PDR1/2 read
{
/*
PORT_START("JOY1")
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) // START
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 A") PORT_PLAYER(1) // A
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 B") PORT_PLAYER(1) // B
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 C") PORT_PLAYER(1) // C
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("P1 R") PORT_PLAYER(1) // R
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 X") PORT_PLAYER(1) // X
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Y") PORT_PLAYER(1) // Y
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Z") PORT_PLAYER(1) // Z
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("P1 L") PORT_PLAYER(1) // L
*/
if ((state->m_smpc.IOSEL1 && offset == 0x75) || (state->m_smpc.IOSEL2 && offset == 0x77))
{
int hshake;
const int shift_bit[4] = { 4, 12, 8, 0 };
const char *const padnames[] = { "JOY1", "JOY2" };
if(offset == 0x75)
hshake = (state->m_smpc.PDR1>>5) & 3;
else
hshake = (state->m_smpc.PDR2>>5) & 3;
if (LOG_SMPC) logerror("SMPC: SH-2 direct mode, returning data for phase %d\n", hshake);
return_data = 0x80 | 0x10 | ((input_port_read(space->machine(), padnames[offset == 0x77])>>shift_bit[hshake]) & 0xf);
}
}
if (offset == 0x33) return_data = state->m_saturn_region;
if (LOG_SMPC) logerror ("cpu %s (PC=%08X) SMPC: Read from Byte Offset %02x (%d) Returns %02x\n", space->device().tag(), cpu_get_pc(&space->device()), offset, offset>>1, return_data);
return return_data;
}
static WRITE8_HANDLER( saturn_SMPC_w8 )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
system_time systime;
UINT8 last;
running_machine &machine = space->machine();
/* get the current date/time from the core */
machine.current_datetime(systime);
if (LOG_SMPC) logerror ("8-bit SMPC Write to Offset %02x (reg %d) with Data %02x (prev %02x)\n", offset, offset>>1, data, state->m_smpc_ram[offset]);
// if (offset == 0x7d) printf("IOSEL2 %d IOSEL1 %d\n", (data>>1)&1, data&1);
last = state->m_smpc_ram[offset];
if ((state->m_smpc.intback_stage > 0) && (offset == 1) && (((data ^ 0x80)&0x80) == (last&0x80)))
{
if (LOG_SMPC) logerror("SMPC: CONTINUE request, stage %d\n", state->m_smpc.intback_stage);
if (state->m_smpc.intback_stage != 3)
{
state->m_smpc.intback_stage = 2;
}
smpc_intbackhelper(machine);
device_set_input_line_and_vector(state->m_maincpu, 8, HOLD_LINE, 0x47);
}
if ((offset == 1) && (data & 0x40))
{
if (LOG_SMPC) logerror("SMPC: BREAK request\n");
state->m_smpc.intback_stage = 0;
}
state->m_smpc_ram[offset] = data;
if (offset == 0x75) // PDR1
{
state->m_smpc.PDR1 = (data & state->m_smpc_ram[0x79]);
}
if (offset == 0x77) // PDR2
{
state->m_smpc.PDR2 = (data & state->m_smpc_ram[0x7b]);
}
if(offset == 0x7d)
{
state->m_smpc.IOSEL1 = state->m_smpc_ram[0x7d] & 1;
state->m_smpc.IOSEL2 = (state->m_smpc_ram[0x7d] & 2) >> 1;
}
if(offset == 0x7f)
{
//enable PAD irq & VDP2 external latch for port 1/2
state->m_smpc.EXLE1 = (state->m_smpc_ram[0x7f] & 1) >> 0;
state->m_smpc.EXLE2 = (state->m_smpc_ram[0x7f] & 2) >> 1;
//if(state->m_smpc.EXLE1 || state->m_smpc.EXLE2)
// cputag_set_input_line_and_vector(space->machine(), "maincpu", 8, (stv_irq.pad) ? HOLD_LINE : CLEAR_LINE, 0x48);
}
if (offset == 0x1f)
{
switch (data)
{
case 0x00:
if(LOG_SMPC) logerror ("SMPC: Master ON\n");
smpc_master_on(space->machine());
break;
//in theory 0x01 is for Master OFF
case 0x02:
case 0x03:
if(LOG_SMPC) logerror ("SMPC: Slave %s\n",(data & 1) ? "off" : "on");
smpc_slave_enable(space->machine(),data & 1);
break;
case 0x06:
case 0x07:
if(LOG_SMPC) logerror ("SMPC: Sound %s\n",(data & 1) ? "off" : "on");
smpc_sound_enable(space->machine(),data & 1);
break;
/*CD (SH-1) ON/OFF,guess that this is needed for Sports Fishing games...*/
//case 0x08:
//case 0x09:
case 0x0d:
if(LOG_SMPC) logerror ("SMPC: System Reset\n");
smpc_system_reset(space->machine());
break;
case 0x0e:
case 0x0f:
if(LOG_SMPC) logerror ("SMPC: Change Clock to %s\n",data & 1 ? "320" : "352");
smpc_change_clock(space->machine(),data & 1);
break;
/*"Interrupt Back"*/
case 0x10:
if(LOG_SMPC) logerror ("SMPC: Status Acquire (IntBack)\n");
space->machine().scheduler().timer_set(attotime::from_msec(16), FUNC(smpc_intback),0); //TODO: variable time
break;
/* RTC write*/
case 0x16:
if(LOG_SMPC) logerror("SMPC: RTC write\n");
smpc_rtc_write(space->machine());
break;
/* SMPC memory setting*/
case 0x17:
if(LOG_SMPC) logerror ("SMPC: memory setting\n");
smpc_memory_setting(space->machine());
break;
case 0x18:
if(LOG_SMPC) logerror ("SMPC: NMI request\n");
smpc_nmi_req(space->machine());
break;
case 0x19:
case 0x1a:
if(LOG_SMPC) logerror ("SMPC: NMI %sable\n",data & 1 ? "Dis" : "En");
smpc_nmi_set(space->machine(),data & 1);
break;
default:
printf ("cpu %s (PC=%08X) SMPC: undocumented Command %02x\n", space->device().tag(), cpu_get_pc(&space->device()), data);
}
// we've processed the command, clear status flag
state->m_smpc_ram[0x5f] = data; //read-back for last command issued
state->m_smpc_ram[0x63] = 0x00;
/*TODO:emulate the timing of each command...*/
}
}
/*
I/O overview:
PORT-A 1st player inputs
@ -1258,21 +541,21 @@ static READ32_HANDLER( saturn_scu_r )
{
if(LOG_SCU) logerror("(PC=%08x) IRQ status reg read %08x\n",cpu_get_pc(&space->device()),mem_mask);
state->m_scu_regs[41] = (stv_irq.vblank_in & 1)<<0;
state->m_scu_regs[41]|= (stv_irq.vblank_out & 1)<<1;
state->m_scu_regs[41]|= (stv_irq.hblank_in & 1)<<2;
state->m_scu_regs[41]|= (stv_irq.timer_0 & 1)<<3;
state->m_scu_regs[41]|= (stv_irq.timer_1 & 1)<<4;
state->m_scu_regs[41]|= (stv_irq.dsp_end & 1)<<5;
state->m_scu_regs[41]|= (stv_irq.sound_req & 1)<<6;
state->m_scu_regs[41]|= (stv_irq.smpc & 1)<<7;
state->m_scu_regs[41]|= (stv_irq.pad & 1)<<8;
state->m_scu_regs[41]|= (stv_irq.dma_end[0] & 1)<<9;
state->m_scu_regs[41]|= (stv_irq.dma_end[1] & 1)<<10;
state->m_scu_regs[41]|= (stv_irq.dma_end[2] & 1)<<11;
state->m_scu_regs[41]|= (stv_irq.dma_ill & 1)<<12;
state->m_scu_regs[41]|= (stv_irq.vdp1_end & 1)<<13;
state->m_scu_regs[41]|= (stv_irq.abus & 1)<<15;
state->m_scu_regs[41] = (state->m_scu_irq.vblank_in & 1)<<0;
state->m_scu_regs[41]|= (state->m_scu_irq.vblank_out & 1)<<1;
state->m_scu_regs[41]|= (state->m_scu_irq.hblank_in & 1)<<2;
state->m_scu_regs[41]|= (state->m_scu_irq.timer_0 & 1)<<3;
state->m_scu_regs[41]|= (state->m_scu_irq.timer_1 & 1)<<4;
state->m_scu_regs[41]|= (state->m_scu_irq.dsp_end & 1)<<5;
state->m_scu_regs[41]|= (state->m_scu_irq.sound_req & 1)<<6;
state->m_scu_regs[41]|= (state->m_scu_irq.smpc & 1)<<7;
state->m_scu_regs[41]|= (state->m_scu_irq.pad & 1)<<8;
state->m_scu_regs[41]|= (state->m_scu_irq.dma_end[0] & 1)<<9;
state->m_scu_regs[41]|= (state->m_scu_irq.dma_end[1] & 1)<<10;
state->m_scu_regs[41]|= (state->m_scu_irq.dma_end[2] & 1)<<11;
state->m_scu_regs[41]|= (state->m_scu_irq.dma_ill & 1)<<12;
state->m_scu_regs[41]|= (state->m_scu_irq.vdp1_end & 1)<<13;
state->m_scu_regs[41]|= (state->m_scu_irq.abus & 1)<<15;
return state->m_scu_regs[41] ^ 0xffffffff; //TODO: this is WRONG (Choice Cuts is a good test case)
}
@ -1367,21 +650,21 @@ static WRITE32_HANDLER( saturn_scu_w )
/*An interrupt is masked when his specific bit is 1.*/
/*Are bit 16-bit 31 for External A-Bus irq mask like the status register?*/
stv_irq.vblank_in = (((state->m_scu_regs[40] & 0x0001)>>0) ^ 1);
stv_irq.vblank_out = (((state->m_scu_regs[40] & 0x0002)>>1) ^ 1);
stv_irq.hblank_in = (((state->m_scu_regs[40] & 0x0004)>>2) ^ 1);
stv_irq.timer_0 = (((state->m_scu_regs[40] & 0x0008)>>3) ^ 1);
stv_irq.timer_1 = (((state->m_scu_regs[40] & 0x0010)>>4) ^ 1);
stv_irq.dsp_end = (((state->m_scu_regs[40] & 0x0020)>>5) ^ 1);
stv_irq.sound_req = (((state->m_scu_regs[40] & 0x0040)>>6) ^ 1);
stv_irq.smpc = (((state->m_scu_regs[40] & 0x0080)>>7) ^ 1); //NOTE: SCU bug
stv_irq.pad = (((state->m_scu_regs[40] & 0x0100)>>8) ^ 1);
stv_irq.dma_end[2] = (((state->m_scu_regs[40] & 0x0200)>>9) ^ 1);
stv_irq.dma_end[1] = (((state->m_scu_regs[40] & 0x0400)>>10) ^ 1);
stv_irq.dma_end[0] = (((state->m_scu_regs[40] & 0x0800)>>11) ^ 1);
stv_irq.dma_ill = (((state->m_scu_regs[40] & 0x1000)>>12) ^ 1);
stv_irq.vdp1_end = (((state->m_scu_regs[40] & 0x2000)>>13) ^ 1);
stv_irq.abus = (((state->m_scu_regs[40] & 0x8000)>>15) ^ 1);
state->m_scu_irq.vblank_in = (((state->m_scu_regs[40] & 0x0001)>>0) ^ 1);
state->m_scu_irq.vblank_out = (((state->m_scu_regs[40] & 0x0002)>>1) ^ 1);
state->m_scu_irq.hblank_in = (((state->m_scu_regs[40] & 0x0004)>>2) ^ 1);
state->m_scu_irq.timer_0 = (((state->m_scu_regs[40] & 0x0008)>>3) ^ 1);
state->m_scu_irq.timer_1 = (((state->m_scu_regs[40] & 0x0010)>>4) ^ 1);
state->m_scu_irq.dsp_end = (((state->m_scu_regs[40] & 0x0020)>>5) ^ 1);
state->m_scu_irq.sound_req = (((state->m_scu_regs[40] & 0x0040)>>6) ^ 1);
state->m_scu_irq.smpc = (((state->m_scu_regs[40] & 0x0080)>>7) ^ 1); //NOTE: SCU bug
state->m_scu_irq.pad = (((state->m_scu_regs[40] & 0x0100)>>8) ^ 1);
state->m_scu_irq.dma_end[2] = (((state->m_scu_regs[40] & 0x0200)>>9) ^ 1);
state->m_scu_irq.dma_end[1] = (((state->m_scu_regs[40] & 0x0400)>>10) ^ 1);
state->m_scu_irq.dma_end[0] = (((state->m_scu_regs[40] & 0x0800)>>11) ^ 1);
state->m_scu_irq.dma_ill = (((state->m_scu_regs[40] & 0x1000)>>12) ^ 1);
state->m_scu_irq.vdp1_end = (((state->m_scu_regs[40] & 0x2000)>>13) ^ 1);
state->m_scu_irq.abus = (((state->m_scu_regs[40] & 0x8000)>>15) ^ 1);
/*Take out the common settings to keep logging quiet.*/
if(state->m_scu_regs[40] != 0xfffffffe &&
@ -1414,21 +697,21 @@ static WRITE32_HANDLER( saturn_scu_w )
/*This is r/w by introdon...*/
if(LOG_SCU) logerror("IRQ status reg set:%08x %08x\n",state->m_scu_regs[41],mem_mask);
stv_irq.vblank_in = ((state->m_scu_regs[41] & 0x0001)>>0);
stv_irq.vblank_out = ((state->m_scu_regs[41] & 0x0002)>>1);
stv_irq.hblank_in = ((state->m_scu_regs[41] & 0x0004)>>2);
stv_irq.timer_0 = ((state->m_scu_regs[41] & 0x0008)>>3);
stv_irq.timer_1 = ((state->m_scu_regs[41] & 0x0010)>>4);
stv_irq.dsp_end = ((state->m_scu_regs[41] & 0x0020)>>5);
stv_irq.sound_req = ((state->m_scu_regs[41] & 0x0040)>>6);
stv_irq.smpc = ((state->m_scu_regs[41] & 0x0080)>>7);
stv_irq.pad = ((state->m_scu_regs[41] & 0x0100)>>8);
stv_irq.dma_end[2] = ((state->m_scu_regs[41] & 0x0200)>>9);
stv_irq.dma_end[1] = ((state->m_scu_regs[41] & 0x0400)>>10);
stv_irq.dma_end[0] = ((state->m_scu_regs[41] & 0x0800)>>11);
stv_irq.dma_ill = ((state->m_scu_regs[41] & 0x1000)>>12);
stv_irq.vdp1_end = ((state->m_scu_regs[41] & 0x2000)>>13);
stv_irq.abus = ((state->m_scu_regs[41] & 0x8000)>>15);
state->m_scu_irq.vblank_in = ((state->m_scu_regs[41] & 0x0001)>>0);
state->m_scu_irq.vblank_out = ((state->m_scu_regs[41] & 0x0002)>>1);
state->m_scu_irq.hblank_in = ((state->m_scu_regs[41] & 0x0004)>>2);
state->m_scu_irq.timer_0 = ((state->m_scu_regs[41] & 0x0008)>>3);
state->m_scu_irq.timer_1 = ((state->m_scu_regs[41] & 0x0010)>>4);
state->m_scu_irq.dsp_end = ((state->m_scu_regs[41] & 0x0020)>>5);
state->m_scu_irq.sound_req = ((state->m_scu_regs[41] & 0x0040)>>6);
state->m_scu_irq.smpc = ((state->m_scu_regs[41] & 0x0080)>>7);
state->m_scu_irq.pad = ((state->m_scu_regs[41] & 0x0100)>>8);
state->m_scu_irq.dma_end[2] = ((state->m_scu_regs[41] & 0x0200)>>9);
state->m_scu_irq.dma_end[1] = ((state->m_scu_regs[41] & 0x0400)>>10);
state->m_scu_irq.dma_end[0] = ((state->m_scu_regs[41] & 0x0800)>>11);
state->m_scu_irq.dma_ill = ((state->m_scu_regs[41] & 0x1000)>>12);
state->m_scu_irq.vdp1_end = ((state->m_scu_regs[41] & 0x2000)>>13);
state->m_scu_irq.abus = ((state->m_scu_regs[41] & 0x8000)>>15);
break;
case 42: if(LOG_SCU) logerror("A-Bus IRQ ACK %08x\n",state->m_scu_regs[42]); break;
@ -1442,7 +725,7 @@ static TIMER_CALLBACK( dma_lv0_ended )
{
saturn_state *state = machine.driver_data<saturn_state>();
if(stv_irq.dma_end[0]) device_set_input_line_and_vector(state->m_maincpu, 5, HOLD_LINE, 0x4b);
if(state->m_scu_irq.dma_end[0]) device_set_input_line_and_vector(state->m_maincpu, 5, HOLD_LINE, 0x4b);
DnMV_0(0);
}
@ -1452,7 +735,7 @@ static TIMER_CALLBACK( dma_lv1_ended )
{
saturn_state *state = machine.driver_data<saturn_state>();
if(stv_irq.dma_end[1]) device_set_input_line_and_vector(state->m_maincpu, 6, HOLD_LINE, 0x4a);
if(state->m_scu_irq.dma_end[1]) device_set_input_line_and_vector(state->m_maincpu, 6, HOLD_LINE, 0x4a);
DnMV_0(1);
}
@ -1462,7 +745,7 @@ static TIMER_CALLBACK( dma_lv2_ended )
{
saturn_state *state = machine.driver_data<saturn_state>();
if(stv_irq.dma_end[2]) device_set_input_line_and_vector(state->m_maincpu, 6, HOLD_LINE, 0x49);
if(state->m_scu_irq.dma_end[2]) device_set_input_line_and_vector(state->m_maincpu, 6, HOLD_LINE, 0x49);
DnMV_0(2);
}
@ -1752,7 +1035,7 @@ static READ8_HANDLER( saturn_cart_type_r )
static ADDRESS_MAP_START( saturn_mem, AS_PROGRAM, 32 )
AM_RANGE(0x00000000, 0x0007ffff) AM_ROM AM_SHARE("share6") // bios
AM_RANGE(0x00100000, 0x0010007f) AM_READWRITE8(saturn_SMPC_r8, saturn_SMPC_w8,0xffffffff)
AM_RANGE(0x00100000, 0x0010007f) AM_READWRITE8(saturn_SMPC_r, saturn_SMPC_w,0xffffffff)
AM_RANGE(0x00180000, 0x0018ffff) AM_READWRITE(saturn_backupram_r, saturn_backupram_w) AM_SHARE("share1") AM_BASE_MEMBER(saturn_state,m_backupram)
AM_RANGE(0x00200000, 0x002fffff) AM_RAM AM_MIRROR(0x100000) AM_SHARE("share2") AM_BASE_MEMBER(saturn_state,m_workram_l)
// AM_RANGE(0x01000000, 0x01000003) AM_MIRROR(0x7ffffc) AM_WRITE(minit_w)
@ -1781,7 +1064,7 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( stv_mem, AS_PROGRAM, 32 )
AM_RANGE(0x00000000, 0x0007ffff) AM_ROM AM_SHARE("share6") // bios
AM_RANGE(0x00100000, 0x0010007f) AM_READWRITE8(stv_SMPC_r8, stv_SMPC_w8,0xffffffff)
AM_RANGE(0x00100000, 0x0010007f) AM_READWRITE8(stv_SMPC_r, stv_SMPC_w,0xffffffff)
AM_RANGE(0x00180000, 0x0018ffff) AM_READWRITE(saturn_backupram_r,saturn_backupram_w) AM_SHARE("share1") AM_BASE_MEMBER(saturn_state,m_backupram)
AM_RANGE(0x00200000, 0x002fffff) AM_RAM AM_MIRROR(0x100000) AM_SHARE("share2") AM_BASE_MEMBER(saturn_state,m_workram_l)
AM_RANGE(0x00400000, 0x0040001f) AM_READWRITE(stv_io_r32, stv_io_w32) AM_BASE_MEMBER(saturn_state,m_ioga) AM_SHARE("share4") AM_MIRROR(0x20)
@ -2380,7 +1663,7 @@ static WRITE_LINE_DEVICE_HANDLER( scsp_to_main_irq )
{
saturn_state *drvstate = device->machine().driver_data<saturn_state>();
if(stv_irq.sound_req)
if(drvstate->m_scu_irq.sound_req)
{
device_set_input_line_and_vector(drvstate->m_maincpu, 9, HOLD_LINE, 0x46);
scu_do_transfer(device->machine(),5);
@ -2585,21 +1868,21 @@ static TIMER_DEVICE_CALLBACK( saturn_scanline )
if(scanline == 0*y_step)
{
if(stv_irq.vblank_out)
if(state->m_scu_irq.vblank_out)
{
device_set_input_line_and_vector(state->m_maincpu, 0xe, (stv_irq.vblank_out) ? HOLD_LINE : CLEAR_LINE , 0x41);
device_set_input_line_and_vector(state->m_maincpu, 0xe, (state->m_scu_irq.vblank_out) ? HOLD_LINE : CLEAR_LINE , 0x41);
scu_do_transfer(timer.machine(),1);
}
}
else if(scanline == vblank_line*y_step)
{
if(stv_irq.vblank_in)
if(state->m_scu_irq.vblank_in)
{
device_set_input_line_and_vector(state->m_maincpu, 0xf, HOLD_LINE ,0x40);
scu_do_transfer(timer.machine(),0);
}
if(stv_irq.vdp1_end)
if(state->m_scu_irq.vdp1_end)
{
device_set_input_line_and_vector(state->m_maincpu, 0x2, HOLD_LINE, 0x4d);
scu_do_transfer(timer.machine(),6);
@ -2608,7 +1891,7 @@ static TIMER_DEVICE_CALLBACK( saturn_scanline )
}
else if((scanline % y_step) == 0 && scanline < vblank_line*y_step)
{
if(stv_irq.hblank_in)
if(state->m_scu_irq.hblank_in)
{
device_set_input_line_and_vector(state->m_maincpu, 0xd, HOLD_LINE, 0x42);
scu_do_transfer(timer.machine(),2);
@ -2617,7 +1900,7 @@ static TIMER_DEVICE_CALLBACK( saturn_scanline )
if(scanline == (state->m_scu_regs[36] & 0x3ff)*y_step)
{
if(stv_irq.timer_0)
if(state->m_scu_irq.timer_0)
{
device_set_input_line_and_vector(state->m_maincpu, 0xc, HOLD_LINE, 0x43 );
scu_do_transfer(timer.machine(),3);
@ -2627,7 +1910,7 @@ static TIMER_DEVICE_CALLBACK( saturn_scanline )
/* TODO: this isn't completely correct */
if((state->m_scu_regs[38] & 0x81) == 0x01 && ((scanline % y_step) == 0))
{
if(stv_irq.timer_1)
if(state->m_scu_irq.timer_1)
{
device_set_input_line_and_vector(state->m_maincpu, 0xb, HOLD_LINE, 0x44 );
scu_do_transfer(timer.machine(),4);

View File

@ -81,6 +81,22 @@ public:
UINT8 intback;
}m_smpc;
struct {
UINT8 vblank_out;
UINT8 vblank_in;
UINT8 hblank_in;
UINT8 timer_0;
UINT8 timer_1;
UINT8 dsp_end;
UINT8 sound_req;
UINT8 smpc;
UINT8 pad;
UINT8 dma_end[3];
UINT8 dma_ill;
UINT8 vdp1_end;
UINT8 abus;
}m_scu_irq;
/* Saturn specific*/
int m_saturn_region;
UINT8 m_cart_type;

717
src/mame/machine/smpc.c Normal file
View File

@ -0,0 +1,717 @@
/************************************************************************************
Sega Saturn SMPC - System Manager and Peripheral Control MCU simulation
The SMPC is actually a 4-bit Hitachi HD404920FS MCU, labeled with a Sega custom
315-5744 (that needs decapping)
MCU simulation by Angelo Salese & R. Belmont
TODO:
- timings;
- fix intback issue with inputs;
- better arrangement of variables;
- clean-ups;
*************************************************************************************/
/* SMPC Addresses
00
01 -w Input Register 0 (IREG)
02
03 -w Input Register 1
04
05 -w Input Register 2
06
07 -w Input Register 3
08
09 -w Input Register 4
0a
0b -w Input Register 5
0c
0d -w Input Register 6
0e
0f
10
11
12
13
14
15
16
17
18
19
1a
1b
1c
1d
1e
1f -w Command Register (COMREG)
20
21 r- Output Register 0 (OREG)
22
23 r- Output Register 1
24
25 r- Output Register 2
26
27 r- Output Register 3
28
29 r- Output Register 4
2a
2b r- Output Register 5
2c
2d r- Output Register 6
2e
2f r- Output Register 7
30
31 r- Output Register 8
32
33 r- Output Register 9
34
35 r- Output Register 10
36
37 r- Output Register 11
38
39 r- Output Register 12
3a
3b r- Output Register 13
3c
3d r- Output Register 14
3e
3f r- Output Register 15
40
41 r- Output Register 16
42
43 r- Output Register 17
44
45 r- Output Register 18
46
47 r- Output Register 19
48
49 r- Output Register 20
4a
4b r- Output Register 21
4c
4d r- Output Register 22
4e
4f r- Output Register 23
50
51 r- Output Register 24
52
53 r- Output Register 25
54
55 r- Output Register 26
56
57 r- Output Register 27
58
59 r- Output Register 28
5a
5b r- Output Register 29
5c
5d r- Output Register 30
5e
5f r- Output Register 31
60
61 r- SR
62
63 rw SF
64
65
66
67
68
69
6a
6b
6c
6d
6e
6f
70
71
72
73
74
75 rw PDR1
76
77 rw PDR2
78
79 -w DDR1
7a
7b -w DDR2
7c
7d -w IOSEL2/1
7e
7f -w EXLE2/1
*/
#include "emu.h"
#include "coreutil.h"
#include "includes/stv.h"
#include "machine/smpc.h"
#include "machine/eeprom.h"
#define LOG_SMPC 0
READ8_HANDLER( stv_SMPC_r )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
int return_data;
return_data = state->m_smpc_ram[offset];
if (offset == 0x61) // ?? many games need this or the controls don't work
return_data = 0x20 ^ 0xff;
if (offset == 0x75)//PDR1 read
return_data = input_port_read(space->machine(), "DSW1");
if (offset == 0x77)//PDR2 read
return_data= (0xfe | space->machine().device<eeprom_device>("eeprom")->read_bit());
// if (offset == 0x33) //country code
// return_data = input_port_read(machine, "FAKE");
//if(LOG_SMPC) logerror ("cpu %s (PC=%08X) SMPC: Read from Byte Offset %02x Returns %02x\n", space->device().tag(), cpu_get_pc(&space->device()), offset, return_data);
return return_data;
}
static TIMER_CALLBACK( stv_bankswitch_state )
{
saturn_state *state = machine.driver_data<saturn_state>();
static const char *const banknames[] = { "game0", "game1", "game2", "game3" };
UINT8* game_region;
if(state->m_prev_bankswitch != param)
{
game_region = machine.region(banknames[param])->base();
if (game_region)
memcpy(machine.region("abus")->base(), game_region, 0x3000000);
else
memset(machine.region("abus")->base(), 0x00, 0x3000000);
state->m_prev_bankswitch = param;
}
}
static void stv_select_game(running_machine &machine, int gameno)
{
machine.scheduler().timer_set(attotime::zero, FUNC(stv_bankswitch_state), gameno);
}
static void smpc_master_on(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
device_set_input_line(state->m_maincpu, INPUT_LINE_RESET, CLEAR_LINE);
}
static void smpc_slave_enable(running_machine &machine,UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
device_set_input_line(state->m_slave, INPUT_LINE_RESET, cmd ? ASSERT_LINE : CLEAR_LINE);
}
static void smpc_sound_enable(running_machine &machine,UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
device_set_input_line(state->m_audiocpu, INPUT_LINE_RESET, cmd ? ASSERT_LINE : CLEAR_LINE);
state->m_en_68k = cmd ^ 1;
}
static void smpc_system_reset(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
/*Only backup ram and SMPC ram are retained after that this command is issued.*/
memset(state->m_scu_regs ,0x00,0x000100);
memset(state->m_scsp_regs,0x00,0x001000);
memset(state->m_sound_ram,0x00,0x080000);
memset(state->m_workram_h,0x00,0x100000);
memset(state->m_workram_l,0x00,0x100000);
memset(state->m_vdp2_regs,0x00,0x040000);
memset(state->m_vdp2_vram,0x00,0x100000);
memset(state->m_vdp2_cram,0x00,0x080000);
memset(state->m_vdp1_vram,0x00,0x100000);
//A-Bus
device_set_input_line(state->m_maincpu, INPUT_LINE_RESET, PULSE_LINE);
}
static void smpc_change_clock(running_machine &machine, UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
UINT32 xtal;
xtal = cmd ? MASTER_CLOCK_320 : MASTER_CLOCK_352;
machine.device("maincpu")->set_unscaled_clock(xtal/2);
machine.device("slave")->set_unscaled_clock(xtal/2);
state->m_vdp2.dotsel = cmd ^ 1;
stv_vdp2_dynamic_res_change(machine);
device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, PULSE_LINE); // ff said this causes nmi, should we set a timer then nmi?
smpc_slave_enable(machine,1);
/* TODO: VDP1 / VDP2 / SCU / SCSP default power ON values */
}
static void smpc_intbackhelper(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
int pad,i;
static const char *const padnames[] = { "JOY1", "JOY2" };
if (state->m_smpc.intback_stage == 1)
{
state->m_smpc.intback_stage++;
return;
}
// if (LOG_SMPC) logerror("SMPC: providing PAD data for intback, pad %d\n", intback_stage-2);
for(i=0;i<2;i++)
{
pad = input_port_read(machine, padnames[i]);
state->m_smpc_ram[0x21+i*8] = 0xf1; // no tap, direct connect
state->m_smpc_ram[0x23+i*8] = 0x02; // saturn pad
state->m_smpc_ram[0x25+i*8] = pad>>8;
state->m_smpc_ram[0x27+i*8] = pad & 0xff;
}
if (state->m_smpc.intback_stage == 3)
{
state->m_smpc.smpcSR = (0x80 | state->m_smpc.pmode); // pad 2, no more data, echo back pad mode set by intback
}
else
{
state->m_smpc.smpcSR = (0xe0 | state->m_smpc.pmode); // pad 1, more data, echo back pad mode set by intback
}
state->m_smpc.intback_stage++;
}
/* sys_type 1 == STV, 0 == SATURN */
static TIMER_CALLBACK( smpc_intback )
{
saturn_state *state = machine.driver_data<saturn_state>();
system_time systime;
machine.base_datetime(systime);
UINT8 sys_type = param;
state->m_smpc_ram[0x21] = (0x80) | ((state->m_NMI_reset & 1) << 6);
if(sys_type == 0)
{
state->m_smpc_ram[0x23] = dec_2_bcd(systime.local_time.year / 100);
state->m_smpc_ram[0x25] = dec_2_bcd(systime.local_time.year % 100);
state->m_smpc_ram[0x27] = (systime.local_time.weekday << 4) | (systime.local_time.month + 1);
state->m_smpc_ram[0x29] = dec_2_bcd(systime.local_time.mday);
state->m_smpc_ram[0x2b] = dec_2_bcd(systime.local_time.hour);
state->m_smpc_ram[0x2d] = dec_2_bcd(systime.local_time.minute);
state->m_smpc_ram[0x2f] = dec_2_bcd(systime.local_time.second);
}
state->m_smpc_ram[0x31]=0x00; //?
//state->m_smpc_ram[0x33]=input_port_read(space->machine(), "FAKE");
state->m_smpc_ram[0x35]= 0 << 7 |
state->m_vdp2.dotsel << 6 |
1 << 5 |
1 << 4 |
0 << 3 | //MSHNMI
1 << 2 |
0 << 1 | //SYSRES
0 << 0; //SOUNDRES
state->m_smpc_ram[0x37]= 0 << 6; //CDRES
state->m_smpc_ram[0x39]=sys_type ? 0xff : state->m_smpc.SMEM[0];
state->m_smpc_ram[0x3b]=sys_type ? 0xff : state->m_smpc.SMEM[1];
state->m_smpc_ram[0x3d]=sys_type ? 0xff : state->m_smpc.SMEM[2];
state->m_smpc_ram[0x3f]=sys_type ? 0xff : state->m_smpc.SMEM[3];
state->m_smpc_ram[0x41]=0xff;
state->m_smpc_ram[0x43]=0xff;
state->m_smpc_ram[0x45]=0xff;
state->m_smpc_ram[0x47]=0xff;
state->m_smpc_ram[0x49]=0xff;
state->m_smpc_ram[0x4b]=0xff;
state->m_smpc_ram[0x4d]=0xff;
state->m_smpc_ram[0x4f]=0xff;
state->m_smpc_ram[0x51]=0xff;
state->m_smpc_ram[0x53]=0xff;
state->m_smpc_ram[0x55]=0xff;
state->m_smpc_ram[0x57]=0xff;
state->m_smpc_ram[0x59]=0xff;
state->m_smpc_ram[0x5b]=0xff;
state->m_smpc_ram[0x5d]=0xff;
if(sys_type == 0)
{
state->m_smpc.smpcSR = 0x60; // peripheral data ready, no reset, etc.
state->m_smpc.pmode = state->m_smpc_ram[1]>>4;
state->m_smpc.intback_stage = 2;
smpc_intbackhelper(machine);
}
// /*This is for RTC,cartridge code and similar stuff...*/
//if(LOG_SMPC) logerror ("Interrupt: System Manager (SMPC) at scanline %04x, Vector 0x47 Level 0x08\n",scanline);
if(state->m_scu_irq.smpc)
device_set_input_line_and_vector(state->m_maincpu, 8, HOLD_LINE, 0x47);
}
static void smpc_rtc_write(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
state->m_smpc_ram[0x2f] = state->m_smpc_ram[0x0d];
state->m_smpc_ram[0x2d] = state->m_smpc_ram[0x0b];
state->m_smpc_ram[0x2b] = state->m_smpc_ram[0x09];
state->m_smpc_ram[0x29] = state->m_smpc_ram[0x07];
state->m_smpc_ram[0x27] = state->m_smpc_ram[0x05];
state->m_smpc_ram[0x25] = state->m_smpc_ram[0x03];
state->m_smpc_ram[0x23] = state->m_smpc_ram[0x01];
}
static void smpc_memory_setting(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
state->m_smpc.SMEM[0] = state->m_smpc_ram[1];
state->m_smpc.SMEM[1] = state->m_smpc_ram[3];
state->m_smpc.SMEM[2] = state->m_smpc_ram[5];
state->m_smpc.SMEM[3] = state->m_smpc_ram[7];
}
static void smpc_nmi_req(running_machine &machine)
{
saturn_state *state = machine.driver_data<saturn_state>();
/*NMI is unconditionally requested?*/
device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, PULSE_LINE);
}
static void smpc_nmi_set(running_machine &machine,UINT8 cmd)
{
saturn_state *state = machine.driver_data<saturn_state>();
state->m_NMI_reset = cmd ^ 1;
state->m_smpc_ram[0x21] = (0x80) | ((state->m_NMI_reset & 1) << 6);
}
WRITE8_HANDLER( stv_SMPC_w )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
system_time systime;
space->machine().base_datetime(systime);
// if(LOG_SMPC) logerror ("8-bit SMPC Write to Offset %02x with Data %02x\n", offset, data);
state->m_smpc_ram[offset] = data;
if(offset == 0x75)
{
/*
-xx- ---- PDR1
---x ---- EEPROM write bit
---- x--- EEPROM CLOCK line
---- -x-- EEPROM CS line
---- --xx A-Bus bank bits
*/
eeprom_device *eeprom = space->machine().device<eeprom_device>("eeprom");
eeprom->set_clock_line((data & 0x08) ? ASSERT_LINE : CLEAR_LINE);
eeprom->write_bit(data & 0x10);
eeprom->set_cs_line((data & 0x04) ? CLEAR_LINE : ASSERT_LINE);
state->m_stv_multi_bank = data & 3;
stv_select_game(space->machine(), state->m_stv_multi_bank);
state->m_smpc.PDR1 = (data & 0x60);
}
if(offset == 0x77)
{
/*
-xx- ---- PDR2
---x ---- Enable Sound System (ACTIVE LOW)
*/
//popmessage("PDR2 = %02x",state->m_smpc_ram[0x77]);
if(LOG_SMPC) logerror("SMPC: M68k %s\n",(state->m_smpc_ram[0x77] & 0x10) ? "off" : "on");
cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_RESET, (state->m_smpc_ram[0x77] & 0x10) ? ASSERT_LINE : CLEAR_LINE);
state->m_en_68k = ((state->m_smpc_ram[0x77] & 0x10) >> 4) ^ 1;
//if(LOG_SMPC) logerror("SMPC: ram [0x77] = %02x\n",state->m_smpc_ram[0x77]);
state->m_smpc.PDR2 = (data & 0x60);
}
if(offset == 0x7d)
{
/*
---- --x- IOSEL2 direct (1) / control mode (0) port select
---- ---x IOSEL1 direct (1) / control mode (0) port select
*/
state->m_smpc.IOSEL1 = (state->m_smpc_ram[0x7d] & 1) >> 0;
state->m_smpc.IOSEL2 = (state->m_smpc_ram[0x7d] & 2) >> 1;
}
if(offset == 0x7f)
{
//enable PAD irq & VDP2 external latch for port 1/2
state->m_smpc.EXLE1 = (state->m_smpc_ram[0x7f] & 1) >> 0;
state->m_smpc.EXLE2 = (state->m_smpc_ram[0x7f] & 2) >> 1;
if(state->m_smpc.EXLE1 || state->m_smpc.EXLE2)
{
//if(LOG_SMPC) logerror ("Interrupt: PAD irq at scanline %04x, Vector 0x48 Level 0x08\n",scanline);
//cputag_set_input_line_and_vector(space->machine(), "maincpu", 8, (state->m_scu_irq.pad) ? HOLD_LINE : CLEAR_LINE, 0x48);
}
}
if (offset == 0x1f) // COMREG
{
switch (data)
{
case 0x00:
if(LOG_SMPC) logerror ("SMPC: Master ON\n");
smpc_master_on(space->machine());
break;
//in theory 0x01 is for Master OFF,but obviously is not used.
case 0x02:
case 0x03:
if(LOG_SMPC) logerror ("SMPC: Slave %s\n",(data & 1) ? "off" : "on");
smpc_slave_enable(space->machine(),(data & 1));
break;
case 0x06:
case 0x07:
if(LOG_SMPC) logerror ("SMPC: Sound %s, ignored\n",(data & 1) ? "off" : "on");
break;
/*CD (SH-1) ON/OFF,guess that this is needed for Sports Fishing games...*/
//case 0x08:
//case 0x09:
case 0x0d:
if(LOG_SMPC) logerror ("SMPC: System Reset\n");
smpc_system_reset(space->machine());
break;
case 0x0e:
case 0x0f:
if(LOG_SMPC) logerror ("SMPC: Change Clock to %s\n",data & 1 ? "320" : "352");
smpc_change_clock(space->machine(),data & 1);
break;
/*"Interrupt Back"*/
case 0x10:
if(LOG_SMPC) logerror ("SMPC: Status Acquire\n");
space->machine().scheduler().timer_set(attotime::from_msec(16), FUNC(smpc_intback),1); //TODO: variable time
break;
/* RTC write*/
case 0x16:
if(LOG_SMPC) logerror("SMPC: RTC write\n");
smpc_rtc_write(space->machine());
break;
/* SMPC memory setting*/
case 0x17:
if(LOG_SMPC) logerror ("SMPC: memory setting\n");
//smpc_memory_setting(space->machine());
break;
case 0x18:
if(LOG_SMPC) logerror ("SMPC: NMI request\n");
smpc_nmi_req(space->machine());
break;
case 0x19:
case 0x1a:
if(LOG_SMPC) logerror ("SMPC: NMI %sable\n",data & 1 ? "Dis" : "En");
smpc_nmi_set(space->machine(),data & 1);
break;
default:
printf ("cpu '%s' (PC=%08X) SMPC: undocumented Command %02x\n", space->device().tag(), cpu_get_pc(&space->device()), data);
}
// we've processed the command, clear status flag
state->m_smpc_ram[0x5f] = data; //read-back command
state->m_smpc_ram[0x63] = 0x00;
/*TODO:emulate the timing of each command...*/
}
}
READ8_HANDLER( saturn_SMPC_r )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
int return_data;
return_data = state->m_smpc_ram[offset];
if ((offset == 0x61))
return_data = state->m_smpc.smpcSR;
if (offset == 0x75 || offset == 0x77)//PDR1/2 read
{
/*
PORT_START("JOY1")
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) // START
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 A") PORT_PLAYER(1) // A
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 B") PORT_PLAYER(1) // B
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 C") PORT_PLAYER(1) // C
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("P1 R") PORT_PLAYER(1) // R
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 X") PORT_PLAYER(1) // X
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Y") PORT_PLAYER(1) // Y
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Z") PORT_PLAYER(1) // Z
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("P1 L") PORT_PLAYER(1) // L
*/
if ((state->m_smpc.IOSEL1 && offset == 0x75) || (state->m_smpc.IOSEL2 && offset == 0x77))
{
int hshake;
const int shift_bit[4] = { 4, 12, 8, 0 };
const char *const padnames[] = { "JOY1", "JOY2" };
if(offset == 0x75)
hshake = (state->m_smpc.PDR1>>5) & 3;
else
hshake = (state->m_smpc.PDR2>>5) & 3;
if (LOG_SMPC) logerror("SMPC: SH-2 direct mode, returning data for phase %d\n", hshake);
return_data = 0x80 | 0x10 | ((input_port_read(space->machine(), padnames[offset == 0x77])>>shift_bit[hshake]) & 0xf);
}
}
if (offset == 0x33) return_data = state->m_saturn_region;
if (LOG_SMPC) logerror ("cpu %s (PC=%08X) SMPC: Read from Byte Offset %02x (%d) Returns %02x\n", space->device().tag(), cpu_get_pc(&space->device()), offset, offset>>1, return_data);
return return_data;
}
WRITE8_HANDLER( saturn_SMPC_w )
{
saturn_state *state = space->machine().driver_data<saturn_state>();
system_time systime;
UINT8 last;
running_machine &machine = space->machine();
/* get the current date/time from the core */
machine.current_datetime(systime);
if (LOG_SMPC) logerror ("8-bit SMPC Write to Offset %02x (reg %d) with Data %02x (prev %02x)\n", offset, offset>>1, data, state->m_smpc_ram[offset]);
// if (offset == 0x7d) printf("IOSEL2 %d IOSEL1 %d\n", (data>>1)&1, data&1);
last = state->m_smpc_ram[offset];
if ((state->m_smpc.intback_stage > 0) && (offset == 1) && (((data ^ 0x80)&0x80) == (last&0x80)))
{
if (LOG_SMPC) logerror("SMPC: CONTINUE request, stage %d\n", state->m_smpc.intback_stage);
if (state->m_smpc.intback_stage != 3)
{
state->m_smpc.intback_stage = 2;
}
smpc_intbackhelper(machine);
device_set_input_line_and_vector(state->m_maincpu, 8, HOLD_LINE, 0x47);
}
if ((offset == 1) && (data & 0x40))
{
if (LOG_SMPC) logerror("SMPC: BREAK request\n");
state->m_smpc.intback_stage = 0;
}
state->m_smpc_ram[offset] = data;
if (offset == 0x75) // PDR1
{
state->m_smpc.PDR1 = (data & state->m_smpc_ram[0x79]);
}
if (offset == 0x77) // PDR2
{
state->m_smpc.PDR2 = (data & state->m_smpc_ram[0x7b]);
}
if(offset == 0x7d)
{
state->m_smpc.IOSEL1 = state->m_smpc_ram[0x7d] & 1;
state->m_smpc.IOSEL2 = (state->m_smpc_ram[0x7d] & 2) >> 1;
}
if(offset == 0x7f)
{
//enable PAD irq & VDP2 external latch for port 1/2
state->m_smpc.EXLE1 = (state->m_smpc_ram[0x7f] & 1) >> 0;
state->m_smpc.EXLE2 = (state->m_smpc_ram[0x7f] & 2) >> 1;
//if(state->m_smpc.EXLE1 || state->m_smpc.EXLE2)
// cputag_set_input_line_and_vector(space->machine(), "maincpu", 8, (state->m_scu_irq.pad) ? HOLD_LINE : CLEAR_LINE, 0x48);
}
if (offset == 0x1f)
{
switch (data)
{
case 0x00:
if(LOG_SMPC) logerror ("SMPC: Master ON\n");
smpc_master_on(space->machine());
break;
//in theory 0x01 is for Master OFF
case 0x02:
case 0x03:
if(LOG_SMPC) logerror ("SMPC: Slave %s\n",(data & 1) ? "off" : "on");
smpc_slave_enable(space->machine(),data & 1);
break;
case 0x06:
case 0x07:
if(LOG_SMPC) logerror ("SMPC: Sound %s\n",(data & 1) ? "off" : "on");
smpc_sound_enable(space->machine(),data & 1);
break;
/*CD (SH-1) ON/OFF,guess that this is needed for Sports Fishing games...*/
//case 0x08:
//case 0x09:
case 0x0d:
if(LOG_SMPC) logerror ("SMPC: System Reset\n");
smpc_system_reset(space->machine());
break;
case 0x0e:
case 0x0f:
if(LOG_SMPC) logerror ("SMPC: Change Clock to %s\n",data & 1 ? "320" : "352");
smpc_change_clock(space->machine(),data & 1);
break;
/*"Interrupt Back"*/
case 0x10:
if(LOG_SMPC) logerror ("SMPC: Status Acquire (IntBack)\n");
space->machine().scheduler().timer_set(attotime::from_msec(16), FUNC(smpc_intback),0); //TODO: variable time
break;
/* RTC write*/
case 0x16:
if(LOG_SMPC) logerror("SMPC: RTC write\n");
smpc_rtc_write(space->machine());
break;
/* SMPC memory setting*/
case 0x17:
if(LOG_SMPC) logerror ("SMPC: memory setting\n");
smpc_memory_setting(space->machine());
break;
case 0x18:
if(LOG_SMPC) logerror ("SMPC: NMI request\n");
smpc_nmi_req(space->machine());
break;
case 0x19:
case 0x1a:
if(LOG_SMPC) logerror ("SMPC: NMI %sable\n",data & 1 ? "Dis" : "En");
smpc_nmi_set(space->machine(),data & 1);
break;
default:
printf ("cpu %s (PC=%08X) SMPC: undocumented Command %02x\n", space->device().tag(), cpu_get_pc(&space->device()), data);
}
// we've processed the command, clear status flag
state->m_smpc_ram[0x5f] = data; //read-back for last command issued
state->m_smpc_ram[0x63] = 0x00;
/*TODO:emulate the timing of each command...*/
}
}

4
src/mame/machine/smpc.h Normal file
View File

@ -0,0 +1,4 @@
WRITE8_HANDLER( stv_SMPC_w );
READ8_HANDLER( stv_SMPC_r );
WRITE8_HANDLER( saturn_SMPC_w );
READ8_HANDLER( saturn_SMPC_r );

View File

@ -1196,7 +1196,7 @@ $(MAMEOBJ)/sega.a: \
$(DRIVERS)/segaybd.o $(VIDEO)/segaybd.o \
$(DRIVERS)/sg1000a.o \
$(DRIVERS)/stactics.o $(VIDEO)/stactics.o \
$(DRIVERS)/saturn.o $(DRIVERS)/stvinit.o $(MACHINE)/stvprot.o $(MACHINE)/stvcd.o $(VIDEO)/stvvdp1.o $(VIDEO)/stvvdp2.o \
$(DRIVERS)/saturn.o $(DRIVERS)/stvinit.o $(MACHINE)/stvprot.o $(MACHINE)/stvcd.o $(MACHINE)/smpc.o $(VIDEO)/stvvdp1.o $(VIDEO)/stvvdp2.o \
$(DRIVERS)/suprloco.o $(VIDEO)/suprloco.o \
$(DRIVERS)/system1.o $(VIDEO)/system1.o \
$(DRIVERS)/system16.o $(VIDEO)/system16.o \