Missed files

This commit is contained in:
Angelo Salese 2011-05-04 18:31:47 +00:00
parent a16d106a97
commit 89bf152dae
4 changed files with 835 additions and 0 deletions

3
.gitattributes vendored
View File

@ -2628,6 +2628,7 @@ src/mame/drivers/vastar.c svneol=native#text/plain
src/mame/drivers/vball.c svneol=native#text/plain
src/mame/drivers/vcombat.c svneol=native#text/plain
src/mame/drivers/vd.c svneol=native#text/plain
src/mame/drivers/vectrex.c svneol=native#text/plain
src/mame/drivers/vega.c svneol=native#text/plain
src/mame/drivers/vegaeo.c svneol=native#text/plain
src/mame/drivers/vegas.c svneol=native#text/plain
@ -3344,6 +3345,7 @@ src/mame/includes/usgames.h svneol=native#text/plain
src/mame/includes/vaportra.h svneol=native#text/plain
src/mame/includes/vastar.h svneol=native#text/plain
src/mame/includes/vball.h svneol=native#text/plain
src/mame/includes/vectrex.h svneol=native#text/plain
src/mame/includes/vendetta.h svneol=native#text/plain
src/mame/includes/vertigo.h svneol=native#text/plain
src/mame/includes/vicdual.h svneol=native#text/plain
@ -4460,6 +4462,7 @@ src/mame/video/vastar.c svneol=native#text/plain
src/mame/video/vball.c svneol=native#text/plain
src/mame/video/vdc.c svneol=native#text/plain
src/mame/video/vdc.h svneol=native#text/plain
src/mame/video/vectrex.c svneol=native#text/plain
src/mame/video/vendetta.c svneol=native#text/plain
src/mame/video/vertigo.c svneol=native#text/plain
src/mame/video/vicdual.c svneol=native#text/plain

233
src/mame/drivers/vectrex.c Normal file
View File

@ -0,0 +1,233 @@
/*****************************************************************
GCE Vectrex
Mathis Rosenhauer
Christopher Salomon (technical advice)
Bruce Tomlin (hardware info)
*****************************************************************/
#include "emu.h"
#include "cpu/m6809/m6809.h"
#include "video/vector.h"
#include "machine/6522via.h"
#include "includes/vectrex.h"
#include "imagedev/cartslot.h"
#include "sound/ay8910.h"
#include "sound/dac.h"
#include "machine/nvram.h"
static ADDRESS_MAP_START(vectrex_map, AS_PROGRAM, 8)
AM_RANGE(0x0000, 0x7fff) AM_ROM
AM_RANGE(0xc800, 0xcbff) AM_RAM AM_MIRROR(0x0400) AM_BASE_MEMBER(vectrex_state, m_gce_vectorram) AM_SIZE_MEMBER(vectrex_state, m_gce_vectorram_size)
AM_RANGE(0xd000, 0xd7ff) AM_READWRITE(vectrex_via_r, vectrex_via_w)
AM_RANGE(0xe000, 0xffff) AM_ROM
ADDRESS_MAP_END
static INPUT_PORTS_START(vectrex)
PORT_START("CONTR1X")
PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_MINMAX(0,0xff) PORT_SENSITIVITY(50) PORT_KEYDELTA(30)
PORT_START("CONTR1Y")
PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_MINMAX(0,0xff) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_REVERSE
PORT_START("CONTR2X")
PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_MINMAX(0,0xff) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_PLAYER(2)
PORT_START("CONTR2Y")
PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_MINMAX(0,0xff) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_REVERSE PORT_PLAYER(2)
PORT_START("BUTTONS")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_PLAYER(1)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_PLAYER(1)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_PLAYER(1)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_PLAYER(2)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_PLAYER(2)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_PLAYER(2)
PORT_START("3DCONF")
PORT_CONFNAME(0x01, 0x00, "3D Imager")
PORT_CONFSETTING(0x00, DEF_STR(Off))
PORT_CONFSETTING(0x01, DEF_STR(On))
PORT_CONFNAME(0x02, 0x00, "Separate images")
PORT_CONFSETTING(0x00, DEF_STR(No))
PORT_CONFSETTING(0x02, DEF_STR(Yes))
PORT_CONFNAME(0x1c, 0x10, "Left eye")
PORT_CONFSETTING(0x00, "Black")
PORT_CONFSETTING(0x04, "Red")
PORT_CONFSETTING(0x08, "Green")
PORT_CONFSETTING(0x0c, "Blue")
PORT_CONFSETTING(0x10, "Color")
PORT_CONFNAME(0xe0, 0x80, "Right eye")
PORT_CONFSETTING(0x00, "Black")
PORT_CONFSETTING(0x20, "Red")
PORT_CONFSETTING(0x40, "Green")
PORT_CONFSETTING(0x60, "Blue")
PORT_CONFSETTING(0x80, "Color")
PORT_START("LPENCONF")
PORT_CONFNAME(0x03, 0x00, "Lightpen")
PORT_CONFSETTING(0x00, DEF_STR(Off))
PORT_CONFSETTING(0x01, "left port")
PORT_CONFSETTING(0x02, "right port")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_CODE(MOUSECODE_BUTTON1)
PORT_START("LPENY")
PORT_BIT(0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(Y, 1, 0, 0) PORT_MINMAX(0,0xff) PORT_SENSITIVITY(35) PORT_KEYDELTA(1) PORT_PLAYER(1)
PORT_START("LPENX")
PORT_BIT(0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(X, 1, 0, 0) PORT_MINMAX(0,0xff) PORT_SENSITIVITY(35) PORT_KEYDELTA(1) PORT_REVERSE PORT_PLAYER(1)
INPUT_PORTS_END
static const ay8910_interface vectrex_ay8910_interface =
{
AY8910_LEGACY_OUTPUT,
AY8910_DEFAULT_LOADS,
DEVCB_INPUT_PORT("BUTTONS"),
DEVCB_NULL,
DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, vectrex_psg_port_w),
DEVCB_NULL
};
static MACHINE_CONFIG_START( vectrex, vectrex_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", M6809, XTAL_6MHz / 4)
MCFG_CPU_PROGRAM_MAP(vectrex_map)
/* video hardware */
MCFG_SCREEN_ADD("screen", VECTOR)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
MCFG_SCREEN_SIZE(400, 300)
MCFG_SCREEN_VISIBLE_AREA(0, 399, 0, 299)
MCFG_SCREEN_UPDATE(vectrex)
MCFG_VIDEO_START(vectrex)
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("dac", DAC, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MCFG_SOUND_ADD("ay8912", AY8912, 1500000)
MCFG_SOUND_CONFIG(vectrex_ay8910_interface)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20)
/* via */
MCFG_VIA6522_ADD("via6522_0", 0, vectrex_via6522_interface)
/* cartridge */
MCFG_CARTSLOT_ADD("cart")
MCFG_CARTSLOT_EXTENSION_LIST("bin,gam,vec")
MCFG_CARTSLOT_NOT_MANDATORY
MCFG_CARTSLOT_LOAD(vectrex_cart)
MCFG_CARTSLOT_INTERFACE("vectrex_cart")
/* software lists */
MCFG_SOFTWARE_LIST_ADD("cart_list","vectrex")
MACHINE_CONFIG_END
ROM_START(vectrex)
ROM_REGION(0x10000,"maincpu", 0)
ROM_LOAD("system.img", 0xe000, 0x2000, CRC(ba13fb57) SHA1(65d07426b520ddd3115d40f255511e0fd2e20ae7))
ROM_END
/*****************************************************************
RA+A Spectrum I+
The Spectrum I+ was a modified Vectrex. It had a 32K ROM cart
and 2K additional battery backed RAM (0x8000 - 0x87ff). PB6
was used to signal inserted coins to the VIA. The unit was
controlled by 8 buttons (2x4 buttons of controller 1 and 2).
Each button had a LED which were mapped to 0xa000.
The srvice mode can be accessed by pressing button
8 during startup. As soon as all LEDs light up,
press 2 and 3 without releasing 8. Then release 8 and
after that 2 and 3. You can leave the screen where you enter
ads by pressing 8 several times.
Character matrix is:
btn| 1 2 3 4 5 6 7 8
---+------------------------
1 | 0 1 2 3 4 5 6 7
2 | 8 9 A B C D E F
3 | G H I J K L M N
4 | O P Q R S T U V
5 | W X Y Z sp ! " #
6 | $ % & ' ( ) * +
7 | , - _ / : ; ? =
8 |bs ret up dn l r hom esc
The first page of ads is shown with the "result" of the
test. Remaining pages are shown in attract mode. If no extra
ram is present, the word COLOR is scrolled in big vector!
letters in attract mode.
*****************************************************************/
static ADDRESS_MAP_START(raaspec_map , AS_PROGRAM, 8)
AM_RANGE(0x0000, 0x7fff) AM_ROM
AM_RANGE(0x8000, 0x87ff) AM_RAM AM_SHARE("nvram")
AM_RANGE(0xa000, 0xa000) AM_WRITE(raaspec_led_w)
AM_RANGE(0xc800, 0xcbff) AM_RAM AM_MIRROR(0x0400) AM_BASE_MEMBER(vectrex_state, m_gce_vectorram) AM_SIZE_MEMBER(vectrex_state, m_gce_vectorram_size)
AM_RANGE(0xd000, 0xd7ff) AM_READWRITE (vectrex_via_r, vectrex_via_w)
AM_RANGE(0xe000, 0xffff) AM_ROM
ADDRESS_MAP_END
static INPUT_PORTS_START(raaspec)
PORT_START("LPENCONF")
PORT_START("LPENY")
PORT_START("LPENX")
PORT_START("3DCONF")
PORT_START("BUTTONS")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON2)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON3)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON4)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON5)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON6)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON7)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_BUTTON8)
PORT_START("COIN")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_COIN1)
INPUT_PORTS_END
static MACHINE_CONFIG_DERIVED( raaspec, vectrex )
MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_PROGRAM_MAP(raaspec_map)
MCFG_NVRAM_ADD_0FILL("nvram")
MCFG_VIDEO_START(raaspec)
/* via */
MCFG_DEVICE_REMOVE("via6522_0")
MCFG_VIA6522_ADD("via6522_0", 0, spectrum1_via6522_interface)
MCFG_DEVICE_REMOVE("cart")
MACHINE_CONFIG_END
ROM_START(raaspec)
ROM_REGION(0x10000,"maincpu", 0)
ROM_LOAD("spectrum.bin", 0x0000, 0x8000, CRC(20af7f3f) SHA1(7ce85db8dd32687ad7629631ae113820371faf7c))
ROM_LOAD("system.img", 0xe000, 0x2000, CRC(ba13fb57) SHA1(65d07426b520ddd3115d40f255511e0fd2e20ae7))
ROM_END
/***************************************************************************
Game driver(s)
***************************************************************************/
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
CONS(1982, vectrex, 0, 0, vectrex, vectrex, vectrex, "General Consumer Electronics", "Vectrex" , ROT270)
CONS(1984, raaspec, vectrex, 0, raaspec, raaspec, vectrex, "Roy Abel & Associates", "Spectrum I+" , ROT270)

103
src/mame/includes/vectrex.h Normal file
View File

@ -0,0 +1,103 @@
/*****************************************************************************
*
* includes/vectrex.h
*
****************************************************************************/
#ifndef VECTREX_H_
#define VECTREX_H_
#include "machine/6522via.h"
#define NVECT 10000
typedef struct _vectrex_point
{
int x; int y;
rgb_t col;
int intensity;
} vectrex_point;
class vectrex_state : public driver_device
{
public:
vectrex_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag) { }
UINT8 *m_gce_vectorram;
size_t m_gce_vectorram_size;
int m_imager_status;
UINT32 m_beam_color;
unsigned char m_via_out[2];
double m_imager_freq;
emu_timer *m_imager_timer;
int m_lightpen_port;
int m_reset_refresh;
rgb_t m_imager_colors[6];
const double *m_imager_angles;
unsigned char m_imager_pinlevel;
int m_old_mcontrol;
double m_sl;
double m_pwl;
int m_x_center;
int m_y_center;
int m_x_max;
int m_y_max;
int m_x_int;
int m_y_int;
int m_lightpen_down;
int m_pen_x;
int m_pen_y;
emu_timer *m_lp_t;
emu_timer *m_refresh;
UINT8 m_blank;
UINT8 m_ramp;
INT8 m_analog[5];
int m_point_index;
int m_display_start;
int m_display_end;
vectrex_point m_points[NVECT];
UINT16 m_via_timer2;
attotime m_vector_start_time;
UINT8 m_cb2;
void (*vector_add_point_function) (running_machine &, int, int, rgb_t, int);
};
/*----------- defined in machine/vectrex.c -----------*/
DEVICE_IMAGE_LOAD( vectrex_cart );
TIMER_CALLBACK(vectrex_imager_eye);
void vectrex_configuration(running_machine &machine);
READ8_DEVICE_HANDLER (vectrex_via_pa_r);
READ8_DEVICE_HANDLER(vectrex_via_pb_r );
void vectrex_via_irq (device_t *device, int level);
WRITE8_HANDLER ( vectrex_psg_port_w );
DRIVER_INIT( vectrex );
/* for spectrum 1+ */
READ8_DEVICE_HANDLER( vectrex_s1_via_pb_r );
/*----------- defined in video/vectrex.c -----------*/
extern const via6522_interface vectrex_via6522_interface;
extern const via6522_interface spectrum1_via6522_interface;
VIDEO_START( vectrex );
SCREEN_UPDATE( vectrex );
VIDEO_START( raaspec );
WRITE8_HANDLER ( raaspec_led_w );
READ8_HANDLER ( vectrex_via_r );
WRITE8_HANDLER ( vectrex_via_w );
void vectrex_add_point_stereo (running_machine &machine, int x, int y, rgb_t color, int intensity);
void vectrex_add_point (running_machine &machine, int x, int y, rgb_t color, int intensity);
#endif /* VECTREX_H_ */

496
src/mame/video/vectrex.c Normal file
View File

@ -0,0 +1,496 @@
#include <math.h>
#include "emu.h"
#include "includes/vectrex.h"
#include "video/vector.h"
#include "machine/6522via.h"
#include "cpu/m6809/m6809.h"
#include "sound/ay8910.h"
#include "sound/dac.h"
#define ANALOG_DELAY 7800
#define INT_PER_CLOCK 550
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.70710678118654752440
#endif
/*********************************************************************
Enums and typedefs
*********************************************************************/
enum {
PORTB = 0,
PORTA
};
enum {
A_X = 0,
A_ZR,
A_Z,
A_AUDIO,
A_Y,
};
/*********************************************************************
Prototypes
*********************************************************************/
static WRITE8_DEVICE_HANDLER (v_via_pa_w);
static WRITE8_DEVICE_HANDLER(v_via_pb_w);
static WRITE8_DEVICE_HANDLER (v_via_ca2_w);
static WRITE8_DEVICE_HANDLER (v_via_cb2_w);
/*********************************************************************
Local variables
*********************************************************************/
const via6522_interface vectrex_via6522_interface =
{
DEVCB_HANDLER(vectrex_via_pa_r), DEVCB_HANDLER(vectrex_via_pb_r), /* read PA/B */
DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, /* read ca1, cb1, ca2, cb2 */
DEVCB_HANDLER(v_via_pa_w), DEVCB_HANDLER(v_via_pb_w), /* write PA/B */
DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(v_via_ca2_w), DEVCB_HANDLER(v_via_cb2_w), /* write ca1, cb1, ca2, cb2 */
DEVCB_LINE(vectrex_via_irq), /* IRQ */
};
/*********************************************************************
Lightpen
*********************************************************************/
static TIMER_CALLBACK(lightpen_trigger)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
if (state->m_lightpen_port & 1)
{
via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
via_0->write_ca1(1);
via_0->write_ca1(0);
}
if (state->m_lightpen_port & 2)
{
cputag_set_input_line(machine, "maincpu", M6809_FIRQ_LINE, PULSE_LINE);
}
}
/*********************************************************************
VIA T2 configuration
We need to snoop the frequency of VIA timer 2 here since most
vectrex games use that timer for steady screen refresh. Even if the
game stops T2 we continue refreshing the screen with the last known
frequency. Note that we quickly get out of sync in this case and the
screen will start flickering (see cut scenes in Spike).
Note that the timer can be adjusted to the full period each time T2
is restarted. This behaviour avoids flicker in most games. Some
games like mine 3d don't work well with this scheme though and show
severe jerking. So the second option is to leave the current period
alone (if the new period isn't shorter) and change only the next
full period.
*********************************************************************/
READ8_HANDLER(vectrex_via_r)
{
via6522_device *via = space->machine().device<via6522_device>("via6522_0");
return via->read(*space, offset);
}
WRITE8_HANDLER(vectrex_via_w)
{
vectrex_state *state = space->machine().driver_data<vectrex_state>();
via6522_device *via = space->machine().device<via6522_device>("via6522_0");
attotime period;
switch (offset)
{
case 8:
state->m_via_timer2 = (state->m_via_timer2 & 0xff00) | data;
break;
case 9:
state->m_via_timer2 = (state->m_via_timer2 & 0x00ff) | (data << 8);
period = (attotime::from_hz(space->machine().device("maincpu")->unscaled_clock()) * state->m_via_timer2);
if (state->m_reset_refresh)
state->m_refresh->adjust(period, 0, period);
else
state->m_refresh->adjust(
min(period, state->m_refresh->remaining()),
0,
period);
break;
}
via->write(*space, offset, data);
}
/*********************************************************************
Screen refresh
*********************************************************************/
static TIMER_CALLBACK(vectrex_refresh)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
/* Refresh only marks the range of vectors which will be drawn
* during the next SCREEN_UPDATE. */
state->m_display_start = state->m_display_end;
state->m_display_end = state->m_point_index;
}
SCREEN_UPDATE(vectrex)
{
vectrex_state *state = screen->machine().driver_data<vectrex_state>();
int i;
vectrex_configuration(screen->machine());
/* start black */
vector_add_point(screen->machine(),
state->m_points[state->m_display_start].x,
state->m_points[state->m_display_start].y,
state->m_points[state->m_display_start].col,
0);
for (i = state->m_display_start; i != state->m_display_end; i = (i + 1) % NVECT)
{
vector_add_point(screen->machine(),
state->m_points[i].x,
state->m_points[i].y,
state->m_points[i].col,
state->m_points[i].intensity);
}
SCREEN_UPDATE_CALL(vector);
vector_clear_list();
return 0;
}
/*********************************************************************
Vector functions
*********************************************************************/
void vectrex_add_point(running_machine &machine, int x, int y, rgb_t color, int intensity)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
vectrex_point *newpoint;
state->m_point_index = (state->m_point_index+1) % NVECT;
newpoint = &state->m_points[state->m_point_index];
newpoint->x = x;
newpoint->y = y;
newpoint->col = color;
newpoint->intensity = intensity;
}
void vectrex_add_point_stereo(running_machine &machine, int x, int y, rgb_t color, int intensity)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
if (state->m_imager_status == 2) /* left = 1, right = 2 */
vectrex_add_point(machine, (int)(y * M_SQRT1_2)+ state->m_x_center,
(int)(((state->m_x_max - x) * M_SQRT1_2)),
color,
intensity);
else
vectrex_add_point(machine, (int)(y * M_SQRT1_2),
(int)((state->m_x_max - x) * M_SQRT1_2),
color,
intensity);
}
static TIMER_CALLBACK(vectrex_zero_integrators)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
state->m_x_int = state->m_x_center + (state->m_analog[A_ZR] * INT_PER_CLOCK);
state->m_y_int = state->m_y_center + (state->m_analog[A_ZR] * INT_PER_CLOCK);
(*state->vector_add_point_function)(machine, state->m_x_int, state->m_y_int, state->m_beam_color, 0);
}
/*********************************************************************
Delayed signals
The RAMP signal is delayed wrt. beam blanking. Getting this right
is important for text placement, the maze in Clean Sweep and many
other games.
*********************************************************************/
static TIMER_CALLBACK(update_signal)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
int length;
if (!state->m_ramp)
{
length = machine.device("maincpu")->unscaled_clock() * INT_PER_CLOCK
* (machine.time() - state->m_vector_start_time).as_double();
state->m_x_int += length * (state->m_analog[A_X] + state->m_analog[A_ZR]);
state->m_y_int += length * (state->m_analog[A_Y] + state->m_analog[A_ZR]);
(*state->vector_add_point_function)(machine, state->m_x_int, state->m_y_int, state->m_beam_color, 2 * state->m_analog[A_Z] * state->m_blank);
}
else
{
if (state->m_blank)
(*state->vector_add_point_function)(machine, state->m_x_int, state->m_y_int, state->m_beam_color, 2 * state->m_analog[A_Z]);
}
state->m_vector_start_time = machine.time();
if (ptr)
* (UINT8 *) ptr = param;
}
/*********************************************************************
Startup
*********************************************************************/
VIDEO_START(vectrex)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
screen_device *screen = machine.first_screen();
const rectangle &visarea = screen->visible_area();
state->m_x_center=((visarea.max_x - visarea.min_x) / 2) << 16;
state->m_y_center=((visarea.max_y - visarea.min_y) / 2) << 16;
state->m_x_max = visarea.max_x << 16;
state->m_y_max = visarea.max_y << 16;
state->m_imager_freq = 1;
state->vector_add_point_function = vectrex_add_point;
state->m_imager_timer = machine.scheduler().timer_alloc(FUNC(vectrex_imager_eye));
state->m_imager_timer->adjust(
attotime::from_hz(state->m_imager_freq),
2,
attotime::from_hz(state->m_imager_freq));
state->m_lp_t = machine.scheduler().timer_alloc(FUNC(lightpen_trigger));
state->m_refresh = machine.scheduler().timer_alloc(FUNC(vectrex_refresh));
VIDEO_START_CALL(vector);
}
/*********************************************************************
VIA interface functions
*********************************************************************/
static void vectrex_multiplexer(running_machine &machine, int mux)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
device_t *dac_device = machine.device("dac");
machine.scheduler().timer_set(attotime::from_nsec(ANALOG_DELAY), FUNC(update_signal), state->m_via_out[PORTA], &state->m_analog[mux]);
if (mux == A_AUDIO)
dac_data_w(dac_device, state->m_via_out[PORTA]);
}
static WRITE8_DEVICE_HANDLER(v_via_pb_w)
{
vectrex_state *state = device->machine().driver_data<vectrex_state>();
if (!(data & 0x80))
{
/* RAMP is active */
if ((state->m_ramp & 0x80))
{
/* RAMP was inactive before */
if (state->m_lightpen_down)
{
/* Simple lin. algebra to check if pen is near
* the line defined by (A_X,A_Y).
* If that is the case, set a timer which goes
* off when the beam reaches the pen. Exact
* timing is important here.
*
* lightpen
* ^
* _ /|
* b / |
* / |
* / |d
* / |
* / |
* ------+---------> beam path
* l | _
* a
*/
double a2, b2, ab, d2;
ab = (state->m_pen_x - state->m_x_int) * state->m_analog[A_X]
+(state->m_pen_y - state->m_y_int) * state->m_analog[A_Y];
if (ab > 0)
{
a2 = (double)(state->m_analog[A_X] * state->m_analog[A_X]
+(double)state->m_analog[A_Y] * state->m_analog[A_Y]);
b2 = (double)(state->m_pen_x - state->m_x_int) * (state->m_pen_x - state->m_x_int)
+(double)(state->m_pen_y - state->m_y_int) * (state->m_pen_y - state->m_y_int);
d2 = b2 - ab * ab / a2;
if (d2 < 2e10 && state->m_analog[A_Z] * state->m_blank > 0)
state->m_lp_t->adjust(attotime::from_double(ab / a2 / (device->machine().device("maincpu")->unscaled_clock() * INT_PER_CLOCK)));
}
}
}
if (!(data & 0x1) && (state->m_via_out[PORTB] & 0x1))
{
/* MUX has been enabled */
device->machine().scheduler().timer_set(attotime::from_nsec(ANALOG_DELAY), FUNC(update_signal));
}
}
else
{
/* RAMP is inactive */
if (!(state->m_ramp & 0x80))
{
/* Cancel running timer, line already finished */
if (state->m_lightpen_down)
state->m_lp_t->adjust(attotime::never);
}
}
/* Sound */
if (data & 0x10)
{
device_t *ay8912 = device->machine().device("ay8912");
if (data & 0x08) /* BC1 (do we select a reg or write it ?) */
ay8910_address_w(ay8912, 0, state->m_via_out[PORTA]);
else
ay8910_data_w(ay8912, 0, state->m_via_out[PORTA]);
}
if (!(data & 0x1) && (state->m_via_out[PORTB] & 0x1))
vectrex_multiplexer (device->machine(), (data >> 1) & 0x3);
state->m_via_out[PORTB] = data;
device->machine().scheduler().timer_set(attotime::from_nsec(ANALOG_DELAY), FUNC(update_signal), data & 0x80, &state->m_ramp);
}
static WRITE8_DEVICE_HANDLER(v_via_pa_w)
{
vectrex_state *state = device->machine().driver_data<vectrex_state>();
/* DAC output always goes to Y integrator */
state->m_via_out[PORTA] = data;
device->machine().scheduler().timer_set(attotime::from_nsec(ANALOG_DELAY), FUNC(update_signal), data, &state->m_analog[A_Y]);
if (!(state->m_via_out[PORTB] & 0x1))
vectrex_multiplexer (device->machine(), (state->m_via_out[PORTB] >> 1) & 0x3);
}
static WRITE8_DEVICE_HANDLER(v_via_ca2_w)
{
if (data == 0)
device->machine().scheduler().timer_set(attotime::from_nsec(ANALOG_DELAY), FUNC(vectrex_zero_integrators));
}
static WRITE8_DEVICE_HANDLER(v_via_cb2_w)
{
vectrex_state *state = device->machine().driver_data<vectrex_state>();
int dx, dy;
if (state->m_cb2 != data)
{
/* Check lightpen */
if (state->m_lightpen_port != 0)
{
state->m_lightpen_down = input_port_read(device->machine(), "LPENCONF") & 0x10;
if (state->m_lightpen_down)
{
state->m_pen_x = input_port_read(device->machine(), "LPENX") * (state->m_x_max / 0xff);
state->m_pen_y = input_port_read(device->machine(), "LPENY") * (state->m_y_max / 0xff);
dx = abs(state->m_pen_x - state->m_x_int);
dy = abs(state->m_pen_y - state->m_y_int);
if (dx < 500000 && dy < 500000 && data > 0)
device->machine().scheduler().timer_set(attotime::zero, FUNC(lightpen_trigger));
}
}
device->machine().scheduler().timer_set(attotime::zero, FUNC(update_signal), data, &state->m_blank);
state->m_cb2 = data;
}
}
/*****************************************************************
RA+A Spectrum I+
*****************************************************************/
const via6522_interface spectrum1_via6522_interface =
{
/*inputs : A/B,CA/B1,CA/B2 */ DEVCB_HANDLER(vectrex_via_pa_r), DEVCB_HANDLER(vectrex_s1_via_pb_r), DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL,
/*outputs: A/B,CA/B1,CA/B2 */ DEVCB_HANDLER(v_via_pa_w), DEVCB_HANDLER(v_via_pb_w), DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(v_via_ca2_w), DEVCB_HANDLER(v_via_cb2_w),
/*irq */ DEVCB_LINE(vectrex_via_irq),
};
WRITE8_HANDLER(raaspec_led_w)
{
logerror("Spectrum I+ LED: %i%i%i%i%i%i%i%i\n",
(data>>7)&0x1, (data>>6)&0x1, (data>>5)&0x1, (data>>4)&0x1,
(data>>3)&0x1, (data>>2)&0x1, (data>>1)&0x1, data&0x1);
}
VIDEO_START(raaspec)
{
vectrex_state *state = machine.driver_data<vectrex_state>();
screen_device *screen = machine.first_screen();
const rectangle &visarea = screen->visible_area();
state->m_x_center=((visarea.max_x - visarea.min_x) / 2) << 16;
state->m_y_center=((visarea.max_y - visarea.min_y) / 2) << 16;
state->m_x_max = visarea.max_x << 16;
state->m_y_max = visarea.max_y << 16;
state->vector_add_point_function = vectrex_add_point;
state->m_refresh = machine.scheduler().timer_alloc(FUNC(vectrex_refresh));
VIDEO_START_CALL(vector);
}