/*
TODO:
- LDV1000 mode
- PR7820 INT/_EXT line
- coin counter
- convert SSI-263 to a sound device
- dump laserdisc
*/
#include "emu.h"
#include "cpu/z80/z80.h"
#include "render.h"
#include "machine/laserdsc.h"
#include "cpu/cop400/cop400.h"
//#include "dlair.lh"
struct ssi263_t
{
UINT8 dr;
UINT8 p;
UINT16 i;
UINT8 r;
UINT8 t;
UINT8 c;
UINT8 a;
UINT8 f;
UINT8 mode;
};
class thayers_state : public driver_device
{
public:
thayers_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag) { }
device_t *m_laserdisc;
UINT8 m_laserdisc_data;
int m_rx_bit;
int m_keylatch;
UINT8 m_cop_data_latch;
int m_cop_data_latch_enable;
UINT8 m_cop_l;
UINT8 m_cop_cmd_latch;
int m_timer_int;
int m_data_rdy_int;
int m_ssi_data_request;
int m_cart_present;
int m_pr7820_enter;
struct ssi263_t m_ssi263;
};
extern const char layout_dlair[];
static const UINT8 led_map[16] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7c, 0x07, 0x7f, 0x67, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x00 };
/* Interrupts */
static void check_interrupt(running_machine &machine)
{
thayers_state *state = machine.driver_data<thayers_state>();
if (!state->m_timer_int || !state->m_data_rdy_int || !state->m_ssi_data_request)
{
cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, HOLD_LINE);
}
else
{
cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, CLEAR_LINE);
}
}
static TIMER_CALLBACK( intrq_tick )
{
cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, CLEAR_LINE);
}
static WRITE8_HANDLER( intrq_w )
{
// T = 1.1 * R30 * C53 = 1.1 * 750K * 0.01uF = 8.25 ms
cputag_set_input_line(space->machine(), "maincpu", INPUT_LINE_IRQ0, HOLD_LINE);
space->machine().scheduler().timer_set(attotime::from_usec(8250), FUNC(intrq_tick));
}
static READ8_HANDLER( irqstate_r )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
0
1
2 SSI263 A/_R
3 tied to +5V
4 _TIMER INT
5 _DATA RDY INT
6 _CART PRES
7
*/
return (state->m_data_rdy_int << 5) | (state->m_timer_int << 4) | 0x08 | (state->m_ssi_data_request << 2);
}
static WRITE8_HANDLER( timer_int_ack_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
state->m_timer_int = 1;
check_interrupt(space->machine());
}
static WRITE8_HANDLER( data_rdy_int_ack_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
state->m_data_rdy_int = 1;
check_interrupt(space->machine());
}
static WRITE8_HANDLER( cop_d_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
D0 _TIMER INT
D1 _DATA RDY INT
D2
D3
*/
if (!BIT(data, 0))
{
state->m_timer_int = 0;
}
if (!BIT(data, 1))
{
state->m_data_rdy_int = 0;
}
check_interrupt(space->machine());
}
/* COP Communication */
static READ8_HANDLER( cop_data_r )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
if (!state->m_cop_data_latch_enable)
{
return state->m_cop_data_latch;
}
else
{
return state->m_cop_l;
}
}
static WRITE8_HANDLER( cop_data_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
state->m_cop_data_latch = data;
}
static READ8_HANDLER( cop_l_r )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
if (!state->m_cop_data_latch_enable)
{
return state->m_cop_data_latch;
}
else
{
return 0;
}
}
static WRITE8_HANDLER( cop_l_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
state->m_cop_l = data;
}
static READ8_HANDLER( cop_g_r )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
G0 U16 Q0
G1 U16 Q1
G2 U16 Q2
G3
*/
return state->m_cop_cmd_latch;
}
static WRITE8_HANDLER( control_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
0
1 _CS128A
2 _BANKSEL1
3
4
5 COP G0
6 COP G1
7 COP G2
*/
state->m_cop_cmd_latch = (data >> 5) & 0x07;
}
static WRITE8_HANDLER( cop_g_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
G0
G1
G2
G3 U17 enable
*/
state->m_cop_data_latch_enable = BIT(data, 3);
}
/* Keyboard */
static READ8_HANDLER(cop_si_r)
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/* keyboard data */
/*
Serial communications format
1, 1, 0, 1, Q8, P0, P1, P2, P3, 0
*/
switch (state->m_rx_bit)
{
case 0:
case 1:
case 3:
return 1;
case 4:
return (state->m_keylatch == 9);
case 5:
case 6:
case 7:
case 8:
{
UINT8 data;
char port[4];
sprintf(port, "R%d", state->m_keylatch);
data = BIT(input_port_read(space->machine(), port), state->m_rx_bit - 5);
return data;
}
default:
return 0;
}
}
static WRITE8_HANDLER( cop_so_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/* keyboard clock */
if (data)
{
state->m_rx_bit++;
if (state->m_rx_bit == 10)
{
state->m_rx_bit = 0;
state->m_keylatch++;
if (state->m_keylatch == 10)
{
state->m_keylatch = 0;
}
}
}
}
/* I/O Board */
static WRITE8_HANDLER( control2_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
0
1 _RESOI (?)
2 _ENCARTDET
3
4
5
6
7
*/
if ((!BIT(data, 2)) & state->m_cart_present)
{
cputag_set_input_line(space->machine(), "maincpu", INPUT_LINE_NMI, HOLD_LINE);
}
}
static READ8_HANDLER( dsw_b_r )
{
return (input_port_read(space->machine(), "COIN") & 0xf0) | (input_port_read(space->machine(), "DSWB") & 0x0f);
}
static READ8_HANDLER( laserdsc_data_r )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
return laserdisc_data_r(state->m_laserdisc);
}
static WRITE8_HANDLER( laserdsc_data_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
state->m_laserdisc_data = data;
}
static WRITE8_HANDLER( laserdsc_control_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
/*
bit description
0
1
2
3
4 coin counter
5 U16 output enable
6 ENTER if switch B5 closed
7 INT/_EXT
*/
coin_counter_w(space->machine(), 0, BIT(data, 4));
if (BIT(data, 5))
{
laserdisc_data_w(state->m_laserdisc, state->m_laserdisc_data);
}
switch (laserdisc_get_type(state->m_laserdisc))
{
case LASERDISC_TYPE_PIONEER_PR7820:
state->m_pr7820_enter = BIT(data, 6) ? CLEAR_LINE : ASSERT_LINE;
laserdisc_line_w(state->m_laserdisc, LASERDISC_LINE_ENTER, state->m_pr7820_enter);
// BIT(data, 7) is INT/_EXT, but there is no such input line in laserdsc.h
break;
case LASERDISC_TYPE_PIONEER_LDV1000:
laserdisc_line_w(state->m_laserdisc, LASERDISC_LINE_ENTER, BIT(data, 7) ? CLEAR_LINE : ASSERT_LINE);
break;
}
}
static WRITE8_HANDLER( den1_w )
{
/*
bit description
0 DD0
1 DD1
2 DD2
3 DD3
4 DA0
5 DA1
6 DA2
7 DA3
*/
output_set_digit_value(data >> 4, led_map[data & 0x0f]);
}
static WRITE8_HANDLER( den2_w )
{
/*
bit description
0 DD0
1 DD1
2 DD2
3 DD3
4 DA0
5 DA1
6 DA2
7 DA3
*/
output_set_digit_value(8 + (data >> 4), led_map[data & 0x0f]);
}
/* SSI-263 */
/*
The following information is from the SSI-263A data sheet.
Thayer's Quest uses an SSI-263, so this might be inaccurate, but it works for now
*/
#define SSI263_CLOCK (XTAL_4MHz/2)
static const char SSI263_PHONEMES[0x40][5] =
{
"PA", "E", "E1", "Y", "YI", "AY", "IE", "I", "A", "AI", "EH", "EH1", "AE", "AE1", "AH", "AH1", "W", "O", "OU", "OO", "IU", "IU1", "U", "U1", "UH", "UH1", "UH2", "UH3", "ER", "R", "R1", "R2",
"L", "L1", "LF", "W", "B", "D", "KV", "P", "T", "K", "HV", "HVC", "HF", "HFC", "HN", "Z", "S", "J", "SCH", "V", "F", "THV", "TH", "M", "N", "NG", ":A", ":OH", ":U", ":UH", "E2", "LB"
};
static TIMER_CALLBACK( ssi263_phoneme_tick )
{
thayers_state *state = machine.driver_data<thayers_state>();
state->m_ssi_data_request = 0;
check_interrupt(machine);
}
static WRITE8_HANDLER( ssi263_register_w )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
struct ssi263_t &ssi263 = state->m_ssi263;
switch (offset)
{
case 0:
{
int frame_time = ((4096 * (16 - ssi263.r)) / 2); // us, /2 should actually be /SSI263_CLOCK, but this way we get microseconds directly
int phoneme_time = frame_time * (4 - ssi263.dr); // us
// duration/phoneme register
ssi263.dr = (data >> 5) & 0x03;
ssi263.p = data & 0x3f;
state->m_ssi_data_request = 1;
check_interrupt(space->machine());
switch (ssi263.mode)
{
case 0:
case 1:
// phoneme timing response
space->machine().scheduler().timer_set(attotime::from_usec(phoneme_time), FUNC(ssi263_phoneme_tick));
break;
case 2:
// frame timing response
space->machine().scheduler().timer_set(attotime::from_usec(frame_time), FUNC(ssi263_phoneme_tick));
break;
case 3:
// disable A/_R output
break;
}
//logerror("SSI263 Phoneme Duration: %u\n", ssi263.dr);
//logerror("SSI263 Phoneme: %02x %s\n", ssi263.p, SSI263_PHONEMES[ssi263.p]);
}
break;
case 1:
// inflection register
ssi263.i = (data << 3) | (ssi263.i & 0x403);
//logerror("SSI263 Inflection: %u\n", ssi263.i);
break;
case 2:
// rate/inflection register
ssi263.i = (BIT(data, 4) << 11) | (ssi263.i & 0x7f8) | (data & 0x07);
ssi263.r = data >> 4;
//logerror("SSI263 Inflection: %u\n", ssi263.i);
//logerror("SSI263 Rate: %u\n", ssi263.r);
break;
case 3:
// control/articulation/amplitude register
if (ssi263.c && !BIT(data, 7))
{
ssi263.mode = ssi263.dr;
switch (ssi263.mode)
{
case 0:
//logerror("SSI263 Phoneme Timing Response, Transitioned Inflection\n");
break;
case 1:
//logerror("SSI263 Phoneme Timing Response, Immediate Inflection\n");
break;
case 2:
// activate A/_R
//logerror("SSI263 Frame Timing Response, Immediate Inflection\n");
break;
case 3:
// disable A/_R output
//logerror("SSI263 A/R Output Disabled\n");
break;
}
}
ssi263.c = BIT(data, 7);
ssi263.t = (data >> 4) & 0x07;
ssi263.a = data & 0x0f;
//logerror("SSI263 Control: %u\n", ssi263.c);
//logerror("SSI263 Articulation: %u\n", ssi263.t);
//logerror("SSI263 Amplitude: %u\n", ssi263.a);
break;
case 4:
case 5:
case 6:
case 7:
// filter frequency register
ssi263.f = data;
//logerror("SSI263 Filter Frequency: %u\n", ssi263.f);
break;
}
}
static READ8_HANDLER( ssi263_register_r )
{
thayers_state *state = space->machine().driver_data<thayers_state>();
// D7 becomes an output, as the inverted state of A/_R. The register address bits are ignored.
return !state->m_ssi_data_request << 7;
}
/* Memory Maps */
static ADDRESS_MAP_START( thayers_map, AS_PROGRAM, 8 )
AM_RANGE(0x0000, 0x7fff) AM_ROM
AM_RANGE(0x8000, 0xbfff) AM_RAM
AM_RANGE(0xc000, 0xdfff) AM_ROM
ADDRESS_MAP_END
static ADDRESS_MAP_START( thayers_io_map, AS_IO, 8 )
ADDRESS_MAP_GLOBAL_MASK(0xff)
AM_RANGE(0x00, 0x07) AM_READWRITE(ssi263_register_r, ssi263_register_w)
AM_RANGE(0x20, 0x20) AM_WRITE(control_w)
AM_RANGE(0x40, 0x40) AM_READWRITE(irqstate_r, control2_w)
AM_RANGE(0x80, 0x80) AM_READWRITE(cop_data_r, cop_data_w)
AM_RANGE(0xa0, 0xa0) AM_WRITE(timer_int_ack_w)
AM_RANGE(0xc0, 0xc0) AM_WRITE(data_rdy_int_ack_w)
AM_RANGE(0xf0, 0xf0) AM_READ(laserdsc_data_r)
AM_RANGE(0xf1, 0xf1) AM_READ(dsw_b_r)
AM_RANGE(0xf2, 0xf2) AM_READ_PORT("DSWA")
AM_RANGE(0xf3, 0xf3) AM_WRITE(intrq_w)
AM_RANGE(0xf4, 0xf4) AM_WRITE(laserdsc_data_w)
AM_RANGE(0xf5, 0xf5) AM_WRITE(laserdsc_control_w)
AM_RANGE(0xf6, 0xf6) AM_WRITE(den1_w)
AM_RANGE(0xf7, 0xf7) AM_WRITE(den2_w)
ADDRESS_MAP_END
static ADDRESS_MAP_START( thayers_cop_io_map, AS_IO, 8 )
AM_RANGE(COP400_PORT_L, COP400_PORT_L) AM_READWRITE(cop_l_r, cop_l_w)
AM_RANGE(COP400_PORT_G, COP400_PORT_G) AM_READWRITE(cop_g_r, cop_g_w)
AM_RANGE(COP400_PORT_D, COP400_PORT_D) AM_WRITE(cop_d_w)
AM_RANGE(COP400_PORT_SK, COP400_PORT_SK) AM_WRITENOP
AM_RANGE(COP400_PORT_SIO, COP400_PORT_SIO) AM_READ(cop_si_r) AM_WRITE(cop_so_w)
ADDRESS_MAP_END
/* Input Ports */
static CUSTOM_INPUT( laserdisc_enter_r )
{
thayers_state *state = field.machine().driver_data<thayers_state>();
switch (laserdisc_get_type(state->m_laserdisc))
{
case LASERDISC_TYPE_PIONEER_PR7820:
return state->m_pr7820_enter;
case LASERDISC_TYPE_PIONEER_LDV1000:
return (laserdisc_line_r(state->m_laserdisc, LASERDISC_LINE_STATUS) == ASSERT_LINE) ? 0 : 1;
}
return 0;
}
static CUSTOM_INPUT( laserdisc_ready_r )
{
thayers_state *state = field.machine().driver_data<thayers_state>();
switch (laserdisc_get_type(state->m_laserdisc))
{
case LASERDISC_TYPE_PIONEER_PR7820:
return (laserdisc_line_r(state->m_laserdisc, LASERDISC_LINE_READY) == ASSERT_LINE) ? 0 : 1;
case LASERDISC_TYPE_PIONEER_LDV1000:
return (laserdisc_line_r(state->m_laserdisc, LASERDISC_LINE_COMMAND) == ASSERT_LINE) ? 0 : 1;
}
return 0;
}
static INPUT_PORTS_START( thayers )
PORT_START("DSWA")
PORT_DIPNAME( 0x07, 0x07, "Time Per Coin" ) PORT_DIPLOCATION( "A:3,2,1" )
PORT_DIPSETTING( 0x07, "110 Seconds" )
PORT_DIPSETTING( 0x06, "95 Seconds" )
PORT_DIPSETTING( 0x05, "80 Seconds" )
PORT_DIPSETTING( 0x04, "70 Seconds" )
PORT_DIPSETTING( 0x03, "60 Seconds" )
PORT_DIPSETTING( 0x02, "45 Seconds" )
PORT_DIPSETTING( 0x01, "30 Seconds" )
PORT_DIPSETTING( 0x00, DEF_STR ( Free_Play ) )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Coinage ) ) PORT_DIPLOCATION( "A:4" )
PORT_DIPSETTING( 0x00, DEF_STR( 2C_1C ) )
PORT_DIPSETTING( 0x08, DEF_STR( 1C_1C ) )
PORT_DIPNAME( 0x10, 0x10, DEF_STR( Lives ) ) PORT_DIPLOCATION( "A:5" )
PORT_DIPSETTING( 0x10, "3" )
PORT_DIPSETTING( 0x00, "5" )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION( "A:6" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x20, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, "Attract Mode Audio" ) PORT_DIPLOCATION( "A:7" )
PORT_DIPSETTING( 0x40, "Always Playing" )
PORT_DIPSETTING( 0x00, "One Out of 8 Times" )
PORT_DIPUNUSED_DIPLOC( 0x80, IP_ACTIVE_LOW, "A:8" )
PORT_START("DSWB")
PORT_SERVICE_DIPLOC( 0x01, 0x01, "B:1" )
PORT_DIPUNUSED_DIPLOC( 0x02, IP_ACTIVE_LOW, "B:2" )
PORT_DIPUNUSED_DIPLOC( 0x04, IP_ACTIVE_LOW, "B:3" )
PORT_DIPNAME( 0x18, 0x00, "LD Player" ) PORT_DIPLOCATION( "B:5,4" )
PORT_DIPSETTING( 0x18, "LDV-1000" )
PORT_DIPSETTING( 0x00, "PR-7820" )
PORT_DIPUNUSED_DIPLOC( 0xe0, IP_ACTIVE_LOW, "B:8,7,6" )
PORT_START("COIN")
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(laserdisc_enter_r, NULL)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(laserdisc_ready_r, NULL)
PORT_START("R0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "2" ) PORT_CODE( KEYCODE_F2 )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "1 - Clear" ) PORT_CODE( KEYCODE_BACKSPACE )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Q" ) PORT_CODE( KEYCODE_Q )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( DEF_STR( Yes ) ) PORT_CODE( KEYCODE_0_PAD )
PORT_START("R1")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Z - Spell of Release" ) PORT_CODE( KEYCODE_Z )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "A" ) PORT_CODE( KEYCODE_A )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "W - Amulet" ) PORT_CODE( KEYCODE_W )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Items" ) PORT_CODE( KEYCODE_1_PAD )
PORT_START("R2")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "X - Scepter" ) PORT_CODE( KEYCODE_X )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "S - Dagger" ) PORT_CODE( KEYCODE_S )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "E - Black Mace" ) PORT_CODE( KEYCODE_E )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Drop Item" ) PORT_CODE( KEYCODE_2_PAD )
PORT_START("R3")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "C - Spell of Seeing" ) PORT_CODE( KEYCODE_C )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "D - Great Circlet" ) PORT_CODE( KEYCODE_D )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "R - Blood Sword" ) PORT_CODE( KEYCODE_R )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Give Score" ) PORT_CODE( KEYCODE_3_PAD )
PORT_START("R4")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "V - Shield" ) PORT_CODE( KEYCODE_V )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "F - Hunting Horn" ) PORT_CODE( KEYCODE_F )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "T - Chalice" ) PORT_CODE( KEYCODE_T )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Replay" ) PORT_CODE( KEYCODE_4_PAD )
PORT_START("R5")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "B - Silver Wheat" ) PORT_CODE( KEYCODE_B )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "G - Long Bow" ) PORT_CODE( KEYCODE_G )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Y - Coins" ) PORT_CODE( KEYCODE_Y )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Combine Action" ) PORT_CODE( KEYCODE_6_PAD )
PORT_START("R6")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "N - Staff" ) PORT_CODE( KEYCODE_N )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "H - Medallion" ) PORT_CODE( KEYCODE_H )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "U - Cold Fire" ) PORT_CODE( KEYCODE_U )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Save Game" ) PORT_CODE( KEYCODE_7_PAD )
PORT_START("R7")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "M - Spell of Understanding" ) PORT_CODE( KEYCODE_M )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "J - Onyx Seal" ) PORT_CODE( KEYCODE_J )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "I - Crown" ) PORT_CODE( KEYCODE_I )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Update" ) PORT_CODE( KEYCODE_8_PAD )
PORT_START("R8")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "3 - Enter" ) PORT_CODE( KEYCODE_ENTER )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "K - Orb of Quoid" ) PORT_CODE( KEYCODE_K )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "O - Crystal" ) PORT_CODE( KEYCODE_O )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "Hint" ) PORT_CODE( KEYCODE_9_PAD )
PORT_START("R9")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "4 - Space" ) PORT_CODE( KEYCODE_SPACE )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "L" ) PORT_CODE( KEYCODE_L )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( "P" ) PORT_CODE( KEYCODE_P )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME( DEF_STR( No ) ) PORT_CODE( KEYCODE_0_PAD )
INPUT_PORTS_END
/* Machine Initialization */
static MACHINE_START( thayers )
{
thayers_state *state = machine.driver_data<thayers_state>();
state->m_laserdisc = machine.device("laserdisc");
memset(&state->m_ssi263, 0, sizeof(state->m_ssi263));
}
static MACHINE_RESET( thayers )
{
thayers_state *state = machine.driver_data<thayers_state>();
int newtype;
state->m_laserdisc_data = 0;
state->m_rx_bit = 0;
state->m_keylatch = 0;
state->m_cop_data_latch = 0;
state->m_cop_data_latch_enable = 0;
state->m_cop_l = 0;
state->m_cop_cmd_latch = 0;
state->m_timer_int = 1;
state->m_data_rdy_int = 1;
state->m_ssi_data_request = 1;
state->m_cart_present = 0;
state->m_pr7820_enter = 0;
newtype = (input_port_read(machine, "DSWB") & 0x18) ? LASERDISC_TYPE_PIONEER_LDV1000 : LASERDISC_TYPE_PIONEER_PR7820;
laserdisc_set_type(state->m_laserdisc, newtype);
}
/* COP400 Interface */
static COP400_INTERFACE( thayers_cop_intf )
{
COP400_CKI_DIVISOR_4, // ???
COP400_CKO_OSCILLATOR_OUTPUT, // ???
COP400_MICROBUS_DISABLED
};
/* Machine Driver */
static MACHINE_CONFIG_START( thayers, thayers_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", Z80, XTAL_4MHz)
MCFG_CPU_PROGRAM_MAP(thayers_map)
MCFG_CPU_IO_MAP(thayers_io_map)
MCFG_CPU_ADD("mcu", COP421, XTAL_4MHz/2) // COP421L-PCA/N
MCFG_CPU_IO_MAP(thayers_cop_io_map)
MCFG_CPU_CONFIG(thayers_cop_intf)
MCFG_MACHINE_START(thayers)
MCFG_MACHINE_RESET(thayers)
MCFG_LASERDISC_ADD("laserdisc", PIONEER_PR7820, "screen", "ldsound")
/* video hardware */
MCFG_LASERDISC_SCREEN_ADD_NTSC("screen", BITMAP_FORMAT_RGB32)
MCFG_PALETTE_LENGTH(256)
/* sound hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
// SSI 263 @ 2MHz
MCFG_SOUND_ADD("ldsound", LASERDISC_SOUND, 0)
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MACHINE_CONFIG_END
/* ROMs */
ROM_START( thayers )
ROM_REGION( 0xe000, "maincpu", 0 )
ROM_LOAD( "tq_u33.bin", 0x0000, 0x8000, CRC(82df5d89) SHA1(58dfd62bf8c5a55d1eba397d2c284e99a4685a3f) )
ROM_LOAD( "tq_u1.bin", 0xc000, 0x2000, CRC(e8e7f566) SHA1(df7b83ef465c65446c8418bc6007447693b75021) )
ROM_REGION( 0x400, "mcu", 0 )
ROM_LOAD( "tq_cop.bin", 0x000, 0x400, CRC(6748e6b3) SHA1(5d7d1ecb57c1501ef6a2d9691eecc9970586606b) )
DISK_REGION( "laserdisc" )
DISK_IMAGE_READONLY( "thayers", 0, NO_DUMP )
ROM_END
ROM_START( thayersa )
ROM_REGION( 0xe000, "maincpu", 0 )
ROM_LOAD( "tq_u33.bin", 0x0000, 0x8000, CRC(82df5d89) SHA1(58dfd62bf8c5a55d1eba397d2c284e99a4685a3f) )
ROM_LOAD( "tq_u1.bin", 0xc000, 0x2000, CRC(33817e25) SHA1(f9750da863dd57fe2f5b6e8fce9c6695dc5c9adc) )
ROM_REGION( 0x400, "mcu", 0 )
ROM_LOAD( "tq_cop.bin", 0x000, 0x400, CRC(6748e6b3) SHA1(5d7d1ecb57c1501ef6a2d9691eecc9970586606b) )
DISK_REGION( "laserdisc" )
DISK_IMAGE_READONLY( "thayers", 0, NO_DUMP )
ROM_END
/* Game Drivers */
/* YEAR NAME PARENT MACHINE INPUT INIT MONITOR COMPANY FULLNAME FLAGS LAYOUT */
GAMEL( 1984, thayers, 0, thayers, thayers, 0, ROT0, "RDI Video Systems", "Thayer's Quest (set 1)", GAME_NOT_WORKING | GAME_NO_SOUND, layout_dlair)
GAMEL( 1984, thayersa, thayers, thayers, thayers, 0, ROT0, "RDI Video Systems", "Thayer's Quest (set 2)", GAME_NOT_WORKING | GAME_NO_SOUND, layout_dlair)