summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/drivers/atarisy4.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/drivers/atarisy4.c')
-rw-r--r--trunk/src/mame/drivers/atarisy4.c1020
1 files changed, 1020 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/atarisy4.c b/trunk/src/mame/drivers/atarisy4.c
new file mode 100644
index 00000000000..28016f80bd2
--- /dev/null
+++ b/trunk/src/mame/drivers/atarisy4.c
@@ -0,0 +1,1020 @@
+/***************************************************************************
+
+ Atari System IV hardware
+
+ preliminary driver by Phil Bennett
+
+ Games supported:
+ * The Last Starfighter (prototype)
+ * Air Race (prototype)
+
+ To do:
+ * Finish video implementation
+ * Find missing HUD/text data for both games
+
+****************************************************************************/
+
+#include "emu.h"
+#include "cpu/m68000/m68000.h"
+#include "cpu/tms32010/tms32010.h"
+#include "video/poly.h"
+
+
+class atarisy4_state : public driver_device
+{
+public:
+ atarisy4_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag) { }
+
+ UINT8 m_r_color_table[256];
+ UINT8 m_g_color_table[256];
+ UINT8 m_b_color_table[256];
+ UINT16 m_dsp_bank[2];
+ UINT8 m_csr[2];
+ UINT16 *m_m68k_ram;
+ UINT16 *m_shared_ram[2];
+ UINT16 *m_screen_ram;
+ poly_manager *m_poly;
+};
+
+
+
+/*************************************
+ *
+ * State
+ *
+ *************************************/
+
+struct _gpu_
+{
+ /* Memory-mapped registers */
+ UINT16 gr[8]; /* Command parameters */
+
+ UINT16 bcrw; /* Screen buffer W control */
+ UINT16 bcrx; /* Screen buffer X control */
+ UINT16 bcry; /* Screen buffer Y control */
+ UINT16 bcrz; /* Screen buffer Z control */
+ UINT16 psrw;
+ UINT16 psrx;
+ UINT16 psry;
+ UINT16 psrz;
+
+ UINT16 dpr;
+ UINT16 ctr;
+ UINT16 lfr;
+ UINT16 ifr;
+ UINT16 ecr; /* Execute command register */
+ UINT16 far;
+ UINT16 mcr; /* Interrupt control */
+ UINT16 qlr;
+ UINT16 qar;
+
+ UINT16 dhr; /* Scanline counter */
+ UINT16 dlr;
+
+ /* Others */
+ UINT16 idr;
+ UINT16 icd;
+
+ UINT8 transpose;
+ UINT8 vblank_wait;
+
+ /* Polygon points */
+ struct
+ {
+ INT16 x;
+ INT16 y;
+ } points[16];
+
+ UINT16 pt_idx;
+ bool poly_open;
+
+ UINT16 clip_min_x;
+ UINT16 clip_max_x;
+ UINT16 clip_min_y;
+ UINT16 clip_max_y;
+} gpu;
+
+
+
+
+typedef struct _poly_extra_data poly_extra_data;
+struct _poly_extra_data
+{
+ UINT16 color;
+ UINT16 *screen_ram;
+};
+
+
+/*************************************
+ *
+ * Forward declarations
+ *
+ *************************************/
+
+static READ16_HANDLER( analog_r );
+static MACHINE_RESET( atarisy4 );
+static MACHINE_RESET( airrace );
+
+
+/*************************************
+ *
+ * Video hardware
+ *
+ *************************************/
+
+static VIDEO_START( atarisy4 )
+{
+ atarisy4_state *state = machine.driver_data<atarisy4_state>();
+ state->m_poly = poly_alloc(machine, 1024, sizeof(poly_extra_data), POLYFLAG_NO_WORK_QUEUE);
+}
+
+static VIDEO_RESET( atarisy4 )
+{
+ gpu.vblank_wait = 0;
+}
+
+static SCREEN_UPDATE( atarisy4 )
+{
+ atarisy4_state *state = screen->machine().driver_data<atarisy4_state>();
+ int y;
+ UINT32 offset = 0;
+
+ if (gpu.bcrw & 0x80)
+ {
+ offset = 0;
+ }
+ else if (gpu.bcrx & 0x80)
+ {
+ offset = 0x10 << 5;
+ }
+
+ //UINT32 offset = gpu.dpr << 5;
+
+ for (y = cliprect->min_y; y <= cliprect->max_y; ++y)
+ {
+ UINT16 *src = &state->m_screen_ram[(offset + (4096 * y)) / 2];
+ UINT32 *dest = BITMAP_ADDR32(bitmap, y, cliprect->min_x);
+ int x;
+
+ for (x = cliprect->min_x; x < cliprect->max_x; x += 2)
+ {
+ UINT16 data = *src++;
+
+ *dest++ = screen->machine().pens[data & 0xff];
+ *dest++ = screen->machine().pens[data >> 8];
+ }
+ }
+ return 0;
+}
+
+INLINE UINT32 xy_to_screen_addr(UINT32 x, UINT32 y)
+{
+// UINT32 offset = ((gpu.mcr >> 4) & 3) << 9;
+ UINT32 offset = 0;
+
+ if (~gpu.bcrw & 0x80)
+ {
+ offset = 0;
+ }
+ else if (~gpu.bcrx & 0x80)
+ {
+ offset = 0x10 << 5;
+ }
+
+ return (y * 4096) + offset + x;
+}
+
+static void image_mem_to_screen(atarisy4_state *state, bool clip)
+{
+ INT16 y = gpu.gr[1] - 0x200;
+ UINT16 h = gpu.gr[3];
+
+ if (h & 0x8000)
+ h = -h;
+
+ /* Not 100% sure of this */
+ while (h--)
+ {
+ UINT16 w = gpu.gr[2];
+ INT16 x = gpu.gr[0] - 0x400;
+
+ if (w & 0x8000)
+ w = -w;
+
+ if (y >= 0 && y <= 511)
+ {
+ while (w--)
+ {
+ if (x >= 0 && x <= 511)
+ {
+ UINT16 pix = state->m_screen_ram[xy_to_screen_addr(x,y) >> 1];
+
+ if (x & 1)
+ pix = (pix & (0x00ff)) | gpu.idr << 8;
+ else
+ pix = (pix & (0xff00)) | gpu.idr;
+
+ state->m_screen_ram[xy_to_screen_addr(x,y) >> 1] = pix;
+ }
+ ++x;
+ }
+ }
+ ++y;
+ }
+}
+
+static void draw_scanline(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid)
+{
+ const poly_extra_data *extra = (const poly_extra_data *)extradata;
+ UINT16 color = extra->color;
+ int x;
+
+ for (x = extent->startx; x < extent->stopx; ++x)
+ {
+ UINT32 addr = xy_to_screen_addr(x, scanline);
+ UINT16 pix = extra->screen_ram[addr >> 1];
+
+ if (x & 1)
+ pix = (pix & (0x00ff)) | color << 8;
+ else
+ pix = (pix & (0xff00)) | color;
+
+ extra->screen_ram[addr >> 1] = pix;
+ }
+}
+
+static void draw_polygon(atarisy4_state *state, UINT16 color)
+{
+ int i;
+ rectangle clip;
+ poly_vertex v1, v2, v3;
+ poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(state->m_poly);
+
+ clip.min_x = 0;
+ clip.min_y = 0;
+ clip.max_x = 511;
+ clip.max_y = 511;
+
+ extra->color = color;
+ extra->screen_ram = state->m_screen_ram;
+
+ v1.x = gpu.points[0].x;
+ v1.y = gpu.points[0].y;
+
+ v2.x = gpu.points[1].x;
+ v2.y = gpu.points[1].y;
+
+ /* Draw a triangle fan */
+ for (i = 2; i <= gpu.pt_idx; ++i)
+ {
+ v3.x = gpu.points[i].x;
+ v3.y = gpu.points[i].y;
+
+ poly_render_triangle(state->m_poly, 0, &clip, draw_scanline, 1, &v1, &v2, &v3);
+ v2 = v3;
+ }
+}
+
+/*
+ GPU commands
+
+ REXP 0x00 Reset expansion
+ SEXP 0x01 Set expansion
+ ROFF 0x02 Reset offset on update
+ SOFF 0x03 Set offset
+ RTPS 0x04 Reset transposition
+ STPS 0x05 Set transposition
+ SIMD 0x06 Load IDR register
+ SICD 0x07 Load partial transfer compare value
+ RCW 0x08 Reset clipping window
+ SCW 0x09 Set clipping window
+ WVB 0x0B Wait for VBlank
+ FXOT 0x10 Fill x offset table
+ FYOT 0x11 Fill y offset table
+ FERT 0x14 Fill expansion table
+ FCT 0x15 Fill color table
+ SMCT 0x16 Screen memory to color table
+ ITSN 0x20 Image memory to screen memory transfer
+ ITSC 0x21 Image memory to screen memory transfer with clip
+ PPA 0x24 Plot point absolute
+ PFOA 0x28 Polygon open absolute
+ PFOR 0x29 Polygon open relative
+ PFVA 0x2A Polygon vector absolute
+ PFVR 0x2B Polygon vector relative
+ PFC 0x2C Polygon close
+*/
+void execute_gpu_command(running_machine &machine)
+{
+ atarisy4_state *state = machine.driver_data<atarisy4_state>();
+ switch (gpu.ecr)
+ {
+ case 0x04:
+ {
+ gpu.transpose = 0;
+ break;
+ }
+ case 0x05:
+ {
+ gpu.transpose = 1;
+ break;
+ }
+ case 0x06:
+ {
+ gpu.idr = gpu.gr[0];
+ break;
+ }
+ case 0x07:
+ {
+ gpu.icd = gpu.gr[0];
+ break;
+ }
+ case 0x09:
+ {
+ gpu.clip_max_x = gpu.gr[0];
+ gpu.clip_min_x = gpu.gr[1];
+ gpu.clip_max_y = gpu.gr[2];
+ gpu.clip_min_y = gpu.gr[3];
+ break;
+ }
+ case 0x0b:
+ {
+ // Wait for VBLANK and swap buffers?
+ gpu.vblank_wait = 1;
+ break;
+ }
+ case 0x16:
+ {
+ /*
+ Copy screen RAM to color RAM
+ GR0 : Color start X
+ GR1 : Color start Y
+ GR2 : Color table offset
+ GR3 : Size
+ GR4 : Channels to set (R: 0x10, G: 0x20, B: 0x40)
+ */
+ int i;
+ int offset = xy_to_screen_addr(gpu.gr[0] - 0x400, gpu.gr[1] - 0x200);
+ int table_offs = gpu.gr[2];
+
+ for (i = 0; i < gpu.gr[3]; ++i)
+ {
+ UINT16 val = state->m_screen_ram[offset >> 1];
+ val >>= (~offset & 1) << 3;
+
+ if (gpu.gr[4] & 0x10)
+ state->m_r_color_table[table_offs] = val;
+ if (gpu.gr[4] & 0x20)
+ state->m_g_color_table[table_offs] = val;
+ if (gpu.gr[4] & 0x40)
+ state->m_b_color_table[table_offs] = val;
+
+ /* Update */
+ palette_set_color(machine, table_offs, MAKE_RGB(state->m_r_color_table[table_offs], state->m_g_color_table[table_offs], state->m_b_color_table[table_offs]));
+
+ ++table_offs;
+ ++offset;
+ }
+
+ break;
+ }
+ case 0x20:
+ {
+ image_mem_to_screen(state, false);
+ break;
+ }
+ case 0x21:
+ {
+ image_mem_to_screen(state, true);
+ break;
+ }
+ case 0x28:
+ {
+ gpu.points[0].x = gpu.gr[0] - 0x400;
+ gpu.points[0].y = gpu.gr[1] - 0x200;
+ gpu.pt_idx = 0;
+ break;
+ }
+ case 0x29:
+ {
+ gpu.points[0].x = gpu.points[gpu.pt_idx].x + gpu.gr[0];
+ gpu.points[0].y = gpu.points[gpu.pt_idx].y + gpu.gr[1];
+ gpu.pt_idx = 0;
+ break;
+ }
+ case 0x2a:
+ {
+ ++gpu.pt_idx;
+ gpu.points[gpu.pt_idx].x = gpu.gr[0] - 0x400;
+ gpu.points[gpu.pt_idx].y = gpu.gr[1] - 0x200;
+ break;
+ }
+ case 0x2b:
+ {
+ UINT16 x = gpu.points[gpu.pt_idx].x + gpu.gr[0];
+ UINT16 y = gpu.points[gpu.pt_idx].y + gpu.gr[1];
+ ++gpu.pt_idx;
+ gpu.points[gpu.pt_idx].x = x;
+ gpu.points[gpu.pt_idx].y = y;
+ break;
+ }
+ case 0x2c:
+ {
+ draw_polygon(state, gpu.gr[2]);
+ poly_wait(state->m_poly, "Normal");
+ break;
+ }
+ default:
+ logerror("GPU COMMAND: %x\n", gpu.ecr);
+ }
+}
+
+static WRITE16_HANDLER( gpu_w )
+{
+ switch (offset)
+ {
+ case 0x00: gpu.gr[0] = data; break;
+ case 0x01: gpu.gr[1] = data; break;
+ case 0x02: gpu.gr[2] = data; break;
+ case 0x03: gpu.gr[3] = data; break;
+ case 0x04: gpu.gr[4] = data; break;
+ case 0x05: gpu.gr[5] = data; break;
+ case 0x06: gpu.gr[6] = data; break;
+ case 0x07: gpu.gr[7] = data; break;
+
+ case 0x08: gpu.bcrw = data; break;
+ case 0x09: gpu.bcrx = data; break;
+ case 0x0a: gpu.bcry = data; break;
+ case 0x0b: gpu.bcrz = data; break;
+ case 0x0c: gpu.psrw = data; break;
+ case 0x0d: gpu.psrx = data; break;
+ case 0x0e: gpu.psry = data; break;
+ case 0x0f: gpu.psrz = data; break;
+
+ case 0x14: gpu.dpr = data; break;
+ case 0x15: gpu.ctr = data; break;
+ case 0x16: gpu.ifr = data; break;
+ case 0x17:
+ {
+ gpu.ecr = data;
+ execute_gpu_command(space->machine());
+ break;
+ }
+ case 0x1a: gpu.far = data; break;
+ case 0x20:
+ {
+ gpu.mcr = data;
+
+ if (~data & 0x08)
+ cputag_set_input_line(space->machine(), "maincpu", 6, CLEAR_LINE);
+
+ break;
+ }
+
+ case 0x21: gpu.qlr = data; break;
+ case 0x22: gpu.qar = data; break;
+ }
+}
+
+static READ16_HANDLER( gpu_r )
+{
+ UINT16 res = 0;
+
+ switch (offset)
+ {
+ case 0x08: res = gpu.bcrw; break;
+ case 0x09: res = gpu.bcrx; break;
+ case 0x0a: res = gpu.bcry; break;
+ case 0x0b: res = gpu.bcrz; break;
+
+ case 0x20: res = gpu.mcr; break;
+
+ case 0x400: res = 5; break; // TODO!
+ case 0x420: res = 5; break;
+
+ default: logerror("GPU_R[%x]\n", offset);
+ }
+
+ return res;
+}
+
+static INTERRUPT_GEN( vblank_int )
+{
+ if (gpu.mcr & 0x08)
+ cputag_set_input_line(device->machine(), "maincpu", 6, ASSERT_LINE);
+}
+
+
+/*************************************
+ *
+ * 68000<->TMS comms
+ *
+ *************************************/
+
+static READ16_HANDLER( m68k_shared_0_r )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ if (!BIT(state->m_csr[0], 3))
+ return (state->m_shared_ram[0][offset]);
+ else
+ return 0xffff;
+}
+
+static WRITE16_HANDLER( m68k_shared_0_w )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ if (!BIT(state->m_csr[0], 3))
+ COMBINE_DATA(&state->m_shared_ram[0][offset]);
+}
+
+static READ16_HANDLER( m68k_shared_1_r )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ if (!BIT(state->m_csr[1], 3))
+ return (state->m_shared_ram[1][offset]);
+ else
+ return 0xffff;
+}
+
+static WRITE16_HANDLER( m68k_shared_1_w )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ if (!BIT(state->m_csr[1], 3))
+ COMBINE_DATA(&state->m_shared_ram[1][offset]);
+}
+
+static READ16_HANDLER( dsp0_status_r )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ return state->m_csr[0];
+}
+
+static WRITE16_HANDLER( dsp0_control_w )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ cputag_set_input_line(space->machine(), "dsp0", INPUT_LINE_RESET, data & 0x01 ? CLEAR_LINE : ASSERT_LINE);
+ cputag_set_input_line(space->machine(), "dsp0", 0, data & 0x02 ? ASSERT_LINE : CLEAR_LINE);
+
+ state->m_csr[0] = data;
+}
+
+static READ16_HANDLER( dsp0_bio_r )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ return BIT(state->m_csr[0], 2);
+}
+
+static WRITE16_HANDLER( dsp0_bank_w )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ if (data & 0x4000)
+ {
+ /* Set TIDONE bit */
+ state->m_csr[0] |= 0x10;
+
+ if (BIT(state->m_csr[0], 5) == 1)
+ fatalerror("68000 interrupt enable was set!");
+ }
+
+ data &= 0x3800;
+ memory_set_bankptr(space->machine(), "dsp0_bank1", &state->m_shared_ram[0][data]);
+ state->m_dsp_bank[0] = data;
+}
+
+static READ16_HANDLER( dsp1_status_r )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ return state->m_csr[1];
+}
+
+static WRITE16_HANDLER( dsp1_control_w )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ cputag_set_input_line(space->machine(), "dsp1", INPUT_LINE_RESET, data & 0x01 ? CLEAR_LINE : ASSERT_LINE);
+ cputag_set_input_line(space->machine(), "dsp1", 0, data & 0x02 ? ASSERT_LINE : CLEAR_LINE);
+
+ state->m_csr[1] = data;
+}
+
+static READ16_HANDLER( dsp1_bio_r )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ return BIT(state->m_csr[1], 2);
+}
+
+static WRITE16_HANDLER( dsp1_bank_w )
+{
+ atarisy4_state *state = space->machine().driver_data<atarisy4_state>();
+ if (data & 0x4000)
+ {
+ /* Set TIDONE bit */
+ state->m_csr[1] |= 0x10;
+
+ if (BIT(state->m_csr[1], 5) == 1)
+ fatalerror("68000 interrupt enable was set!");
+ }
+
+ data &= 0x3800;
+ memory_set_bankptr(space->machine(), "dsp1_bank1", &state->m_shared_ram[1][data]);
+ state->m_dsp_bank[1] = data;
+}
+
+
+/*************************************
+ *
+ * Main CPU memory map
+ *
+ *************************************/
+
+static ADDRESS_MAP_START( main_map, AS_PROGRAM, 16 )
+ AM_RANGE(0x000000, 0x00ffff) AM_RAM AM_BASE_MEMBER(atarisy4_state, m_m68k_ram)
+ AM_RANGE(0x010000, 0x01ffff) AM_RAM
+ AM_RANGE(0x580000, 0x580001) AM_READ_PORT("JOYSTICK")
+ AM_RANGE(0x588000, 0x588001) AM_READ(analog_r)
+ AM_RANGE(0x598000, 0x598001) AM_NOP /* Sound board */
+ AM_RANGE(0x7c0000, 0x7c4fff) AM_READWRITE(m68k_shared_1_r, m68k_shared_1_w)
+ AM_RANGE(0x7c6000, 0x7c6001) AM_READWRITE(dsp1_status_r, dsp1_control_w)
+ AM_RANGE(0x7f0000, 0x7f4fff) AM_READWRITE(m68k_shared_0_r, m68k_shared_0_w)
+ AM_RANGE(0x7f6000, 0x7f6001) AM_READWRITE(dsp0_status_r, dsp0_control_w)
+ AM_RANGE(0xa00400, 0xbfffff) AM_RAM AM_BASE_MEMBER(atarisy4_state, m_screen_ram)
+ AM_RANGE(0xff8000, 0xff8fff) AM_READWRITE(gpu_r, gpu_w)
+ADDRESS_MAP_END
+
+
+/*************************************
+ *
+ * Mathbox DSP memory map
+ *
+ *************************************/
+
+static ADDRESS_MAP_START( dsp0_map, AS_PROGRAM, 16 )
+ ADDRESS_MAP_GLOBAL_MASK(0xfff)
+ AM_RANGE(0x0000, 0x07ff) AM_RAMBANK("dsp0_bank0")
+ AM_RANGE(0x0800, 0x0fff) AM_RAMBANK("dsp0_bank1")
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( dsp0_io_map, AS_IO, 16 )
+ AM_RANGE(0x00, 0x01) AM_WRITE(dsp0_bank_w)
+ AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(dsp0_bio_r)
+ADDRESS_MAP_END
+
+
+/*************************************
+ *
+ * Mathbox DSP memory map
+ *
+ *************************************/
+
+static ADDRESS_MAP_START( dsp1_map, AS_PROGRAM, 16 )
+ ADDRESS_MAP_GLOBAL_MASK(0xfff)
+ AM_RANGE(0x0000, 0x07ff) AM_RAMBANK("dsp1_bank0")
+ AM_RANGE(0x0800, 0x0fff) AM_RAMBANK("dsp1_bank1")
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( dsp1_io_map, AS_IO, 16 )
+ AM_RANGE(0x00, 0x01) AM_WRITE(dsp1_bank_w)
+ AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(dsp1_bio_r)
+ADDRESS_MAP_END
+
+
+/*************************************
+ *
+ * Input ports
+ *
+ *************************************/
+
+ static READ16_HANDLER( analog_r )
+{
+ return (input_port_read(space->machine(), "STICKX") << 8) | input_port_read(space->machine(), "STICKY");
+}
+
+static INPUT_PORTS_START( atarisy4 )
+ PORT_START("JOYSTICK")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_LEFT )
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_RIGHT )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_DOWN )
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_UP )
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_LEFT )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_RIGHT )
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_DOWN )
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_UP )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON1 )
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON2 )
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON3 )
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON4 )
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON5 )
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON6 )
+
+ PORT_START("STICKY")
+ PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(5)
+
+ PORT_START("STICKX")
+ PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(5)
+INPUT_PORTS_END
+
+
+/*************************************
+ *
+ * Machine driver
+ *
+ *************************************/
+
+static MACHINE_CONFIG_START( atarisy4, atarisy4_state )
+ MCFG_CPU_ADD("maincpu", M68000, 8000000)
+ MCFG_CPU_PROGRAM_MAP(main_map)
+ MCFG_CPU_VBLANK_INT("screen", vblank_int)
+
+ MCFG_CPU_ADD("dsp0", TMS32010, 16000000)
+ MCFG_CPU_PROGRAM_MAP(dsp0_map)
+ MCFG_CPU_IO_MAP(dsp0_io_map)
+
+ MCFG_VIDEO_RESET(atarisy4)
+ MCFG_MACHINE_RESET(atarisy4)
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(32000000/2, 660, 0, 512, 404, 0, 384)
+ MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK)
+ MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
+ MCFG_SCREEN_UPDATE(atarisy4)
+ MCFG_PALETTE_LENGTH(256)
+
+ MCFG_VIDEO_START(atarisy4)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( airrace, atarisy4 )
+
+ MCFG_CPU_ADD("dsp1", TMS32010, 16000000)
+ MCFG_CPU_PROGRAM_MAP(dsp1_map)
+ MCFG_CPU_IO_MAP(dsp1_io_map)
+
+ MCFG_MACHINE_RESET(airrace)
+MACHINE_CONFIG_END
+
+
+/*************************************
+ *
+ * ROM definition(s)
+ *
+ *************************************/
+
+ROM_START( laststar )
+ ROM_REGION( 0x20000, "code", 0 )
+ ROM_LOAD( "demo.hex", 0x00000, 0x1c2c4, CRC(7f9e344e) SHA1(ff1462f4f3fa01c47b74d365c240b1c3fdd36755) )
+
+ ROM_REGION( 0x20000, "data", 0 )
+ ROM_LOAD( "data1.hex", 0x00000, 0x077cb, CRC(0e75efc0) SHA1(badfcadd92625637bb3223bee986a29428c8d35a) )
+
+ ROM_REGION( 0x20000, "dsp", 0 )
+ ROM_LOAD( "mathbs.lda", 0x00000, 0x01e00, CRC(4378739a) SHA1(7c360da99a1366a3315f4846244ed3b2514ef7ec) )
+
+ ROM_REGION( 0x20000, "gfx", 0 )
+ ROM_LOAD( "2d_data", 0x00000, 0x077cb, NO_DUMP )
+ROM_END
+
+
+ROM_START( airrace )
+ ROM_REGION( 0x30000, "code", 0 )
+ ROM_LOAD( "demo.hex", 0x00000, 0x25d23, CRC(937fa025) SHA1(c393a05645ad5df9268f03fffad294477e6f090b) )
+
+ ROM_REGION( 0x20000, "dsp", 0 )
+ ROM_LOAD( "mathbs.lda", 0x00000, 0x01e00, CRC(d215acd4) SHA1(853e792b343dc6bcb5b11d455af478a79edfd740) )
+
+ ROM_REGION( 0x20000, "gfx", 0 )
+ ROM_LOAD( "2d_data", 0x00000, 0x077cb, NO_DUMP )
+ROM_END
+
+
+/*************************************
+ *
+ * Driver initialization
+ *
+ *************************************/
+
+INLINE UINT8 hex_to_ascii(UINT8 in)
+{
+ if (in < 0x3a)
+ return in - 0x30;
+ else if (in < 0x47)
+ return in - 0x37;
+ else
+ return in;
+}
+
+void load_ldafile(address_space *space, const UINT8 *file)
+{
+#define READ_CHAR() file[i++]
+ int i = 0;
+
+ while (true)
+ {
+ UINT8 c;
+ UINT8 sum = 1;
+ UINT16 len;
+ UINT16 addr;
+
+ if (READ_CHAR() != 0x01)
+ fatalerror("Bad .LDA file");
+
+ if (READ_CHAR() != 0x00)
+ fatalerror("Bad .LDA file");
+
+ len = READ_CHAR();
+ sum += len;
+
+ c = READ_CHAR();
+ len |= c << 8;
+ sum += c;
+
+ /* End of file */
+ if (len == 6)
+ break;
+
+ addr = READ_CHAR();
+ sum += addr;
+
+ c = READ_CHAR();
+ addr |= c << 8;
+ sum += c;
+
+ len -= 6;
+
+ addr <<= 1;
+ do
+ {
+ UINT8 data = READ_CHAR();
+ sum += data;
+ space->write_byte(addr++, data);
+ } while (--len);
+
+ sum += READ_CHAR();
+
+ if (sum != 0)
+ fatalerror(".LDA checksum failure");
+ }
+}
+
+/* Load memory space with data from a Tektronix-Extended HEX file */
+void load_hexfile(address_space *space, const UINT8 *file)
+{
+#define READ_HEX_CHAR() hex_to_ascii(file[i++])
+
+ UINT32 i = 0;
+ UINT32 line = 1;
+ bool end = false;
+
+ while (true)
+ {
+ UINT8 len;
+ UINT8 record;
+ UINT8 checksum;
+ UINT8 sum = 0;
+ UINT8 addr_len;
+ UINT32 addr = 0;
+
+ /* Ignore blank lines */
+ while (file[i] == '\n') i++;
+
+ /* First character of each line should be a '%' */
+ if (file[i++] != '%')
+ fatalerror("Error on line %d - invalid line start character", line);
+
+ /* Get the line length */
+ len = READ_HEX_CHAR() << 4;
+ len |= READ_HEX_CHAR();
+
+ sum += len & 0xf;
+ sum += len >> 4;
+
+ /* Get the record type */
+ record = READ_HEX_CHAR();
+ sum += record;
+
+ /* Record type */
+ if (record == 8)
+ {
+ end = true;
+ }
+ else if (record == 3)
+ {
+ /* Ignore this type */
+ i += len - 2;
+ goto next_line;
+ }
+ else if (record != 6)
+ {
+ fatalerror("Error on line %d - Invalid record type %d\n", line, record);
+ }
+
+ /* Get the checksum for this line */
+ checksum = READ_HEX_CHAR() << 4;
+ checksum |= READ_HEX_CHAR();
+
+ /* Get the number of address digits */
+ addr_len = READ_HEX_CHAR();
+ sum += addr_len;
+
+ len = len - 6 - addr_len;
+
+ /* Form the address */
+ while (addr_len)
+ {
+ UINT8 digit;
+
+ addr <<= 4;
+ digit = READ_HEX_CHAR();
+ sum += digit;
+ addr |= digit;
+ --addr_len;
+ }
+
+ /* Now read the data */
+ while (len)
+ {
+ UINT8 data;
+
+ data = READ_HEX_CHAR() << 4;
+ data |= READ_HEX_CHAR();
+ sum += data >> 4;
+ sum += data & 0xf;
+
+ if (record == 6)
+ space->write_byte(addr++, data);
+
+ len -= 2;
+ }
+
+ /* Eat the carriage return */
+ ++i;
+
+ if (sum != checksum)
+ fatalerror("Checksum mismatch on line %d (Found 0x%.2x but expected 0x%.2x)\n", line, sum, checksum);
+
+next_line:
+ ++line;
+
+ if (end == true)
+ break;
+ }
+}
+
+static DRIVER_INIT( laststar )
+{
+ atarisy4_state *state = machine.driver_data<atarisy4_state>();
+ address_space *main = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* Allocate 16kB of shared RAM */
+ state->m_shared_ram[0] = auto_alloc_array_clear(machine, UINT16, 0x2000);
+
+ /* Populate the 68000 address space with data from the HEX files */
+ load_hexfile(main, machine.region("code")->base());
+ load_hexfile(main, machine.region("data")->base());
+
+ /* Set up the DSP */
+ memory_set_bankptr(machine, "dsp0_bank0", state->m_shared_ram[0]);
+ memory_set_bankptr(machine, "dsp0_bank1", &state->m_shared_ram[0][0x800]);
+ load_ldafile(machine.device("dsp0")->memory().space(AS_PROGRAM), machine.region("dsp")->base());
+}
+
+static DRIVER_INIT( airrace )
+{
+ atarisy4_state *state = machine.driver_data<atarisy4_state>();
+ /* Allocate two sets of 32kB shared RAM */
+ state->m_shared_ram[0] = auto_alloc_array_clear(machine, UINT16, 0x4000);
+ state->m_shared_ram[1] = auto_alloc_array_clear(machine, UINT16, 0x4000);
+
+ /* Populate RAM with data from the HEX files */
+ load_hexfile(machine.device("maincpu")->memory().space(AS_PROGRAM), machine.region("code")->base());
+
+ /* Set up the first DSP */
+ memory_set_bankptr(machine, "dsp0_bank0", state->m_shared_ram[0]);
+ memory_set_bankptr(machine, "dsp0_bank1", &state->m_shared_ram[0][0x800]);
+ load_ldafile(machine.device("dsp0")->memory().space(AS_PROGRAM), machine.region("dsp")->base());
+
+ /* Set up the second DSP */
+ memory_set_bankptr(machine, "dsp1_bank0", state->m_shared_ram[1]);
+ memory_set_bankptr(machine, "dsp1_bank1", &state->m_shared_ram[1][0x800]);
+ load_ldafile(machine.device("dsp1")->memory().space(AS_PROGRAM), machine.region("dsp")->base());
+}
+
+static MACHINE_RESET( atarisy4 )
+{
+ cputag_set_input_line(machine, "dsp0", INPUT_LINE_RESET, ASSERT_LINE);
+}
+
+static MACHINE_RESET( airrace )
+{
+ cputag_set_input_line(machine, "dsp0", INPUT_LINE_RESET, ASSERT_LINE);
+ cputag_set_input_line(machine, "dsp1", INPUT_LINE_RESET, ASSERT_LINE);
+}
+
+
+/*************************************
+ *
+ * Game driver(s)
+ *
+ *************************************/
+
+GAME( 1984, laststar, 0, atarisy4, atarisy4, laststar, ROT0, "Atari Games", "The Last Starfighter (prototype)", GAME_IMPERFECT_GRAPHICS | GAME_NO_SOUND_HW )
+GAME( 1985, airrace, 0, airrace, atarisy4, airrace, ROT0, "Atari Games", "Air Race (prototype)", GAME_IMPERFECT_GRAPHICS | GAME_NO_SOUND_HW )