26
26
#define SPRITE_COUNT (0x28)
30
UINT8 *exidy440_scanline;
31
UINT8 *exidy440_imageram;
32
UINT8 exidy440_firq_vblank;
33
UINT8 exidy440_firq_beam;
34
UINT8 *topsecex_yscroll;
36
/* local allocated storage */
37
static UINT8 exidy440_latched_x;
38
static UINT8 *local_videoram;
39
static UINT8 *local_paletteram;
42
static UINT8 firq_enable;
43
static UINT8 firq_select;
44
static UINT8 palettebank_io;
45
static UINT8 palettebank_vis;
47
29
/* function prototypes */
48
static void exidy440_update_firq(running_machine *machine);
30
static void exidy440_update_firq(running_machine &machine);
58
40
static VIDEO_START( exidy440 )
42
exidy440_state *state = machine.driver_data<exidy440_state>();
60
43
/* reset the system */
65
exidy440_firq_vblank = 0;
66
exidy440_firq_beam = 0;
44
state->m_firq_enable = 0;
45
state->m_firq_select = 0;
46
state->m_palettebank_io = 0;
47
state->m_palettebank_vis = 0;
48
state->m_firq_vblank = 0;
49
state->m_firq_beam = 0;
68
51
/* allocate a buffer for VRAM */
69
local_videoram = auto_alloc_array(machine, UINT8, 256 * 256 * 2);
70
memset(local_videoram, 0, 256 * 256 * 2);
52
state->m_local_videoram = auto_alloc_array(machine, UINT8, 256 * 256 * 2);
53
memset(state->m_local_videoram, 0, 256 * 256 * 2);
72
55
/* allocate a buffer for palette RAM */
73
local_paletteram = auto_alloc_array(machine, UINT8, 512 * 2);
74
memset(local_paletteram, 0, 512 * 2);
56
state->m_local_paletteram = auto_alloc_array(machine, UINT8, 512 * 2);
57
memset(state->m_local_paletteram, 0, 512 * 2);
78
61
static VIDEO_START( topsecex )
63
exidy440_state *state = machine.driver_data<exidy440_state>();
80
64
VIDEO_START_CALL(exidy440);
82
*topsecex_yscroll = 0;
66
*state->m_topsecex_yscroll = 0;
93
77
READ8_HANDLER( exidy440_videoram_r )
95
UINT8 *base = &local_videoram[(*exidy440_scanline * 256 + offset) * 2];
79
exidy440_state *state = space->machine().driver_data<exidy440_state>();
80
UINT8 *base = &state->m_local_videoram[(*state->m_scanline * 256 + offset) * 2];
97
82
/* combine the two pixel values into one byte */
98
83
return (base[0] << 4) | base[1];
102
87
WRITE8_HANDLER( exidy440_videoram_w )
104
UINT8 *base = &local_videoram[(*exidy440_scanline * 256 + offset) * 2];
89
exidy440_state *state = space->machine().driver_data<exidy440_state>();
90
UINT8 *base = &state->m_local_videoram[(*state->m_scanline * 256 + offset) * 2];
106
92
/* expand the two pixel values into two bytes */
107
93
base[0] = (data >> 4) & 15;
119
105
READ8_HANDLER( exidy440_paletteram_r )
121
return local_paletteram[palettebank_io * 512 + offset];
107
exidy440_state *state = space->machine().driver_data<exidy440_state>();
108
return state->m_local_paletteram[state->m_palettebank_io * 512 + offset];
125
112
WRITE8_HANDLER( exidy440_paletteram_w )
114
exidy440_state *state = space->machine().driver_data<exidy440_state>();
127
115
/* update palette ram in the I/O bank */
128
local_paletteram[palettebank_io * 512 + offset] = data;
116
state->m_local_paletteram[state->m_palettebank_io * 512 + offset] = data;
130
118
/* if we're modifying the active palette, change the color immediately */
131
if (palettebank_io == palettebank_vis)
119
if (state->m_palettebank_io == state->m_palettebank_vis)
135
123
/* combine two bytes into a word */
136
offset = palettebank_vis * 512 + (offset & 0x1fe);
137
word = (local_paletteram[offset] << 8) + local_paletteram[offset + 1];
124
offset = state->m_palettebank_vis * 512 + (offset & 0x1fe);
125
word = (state->m_local_paletteram[offset] << 8) + state->m_local_paletteram[offset + 1];
139
127
/* extract the 5-5-5 RGB colors */
140
palette_set_color_rgb(space->machine, offset / 2, pal5bit(word >> 10), pal5bit(word >> 5), pal5bit(word >> 0));
128
palette_set_color_rgb(space->machine(), offset / 2, pal5bit(word >> 10), pal5bit(word >> 5), pal5bit(word >> 0));
152
140
READ8_HANDLER( exidy440_horizontal_pos_r )
142
exidy440_state *state = space->machine().driver_data<exidy440_state>();
154
143
/* clear the FIRQ on a read here */
155
exidy440_firq_beam = 0;
156
exidy440_update_firq(space->machine);
144
state->m_firq_beam = 0;
145
exidy440_update_firq(space->machine());
158
147
/* according to the schems, this value is only latched on an FIRQ
159
148
* caused by collision or beam */
160
return exidy440_latched_x;
149
return state->m_latched_x;
169
158
* caused by collision or beam, ORed together with CHRCLK,
170
159
* which probably goes off once per scanline; for now, we just
171
160
* always return the current scanline */
172
result = space->machine->primary_screen->vpos();
161
result = space->machine().primary_screen->vpos();
173
162
return (result < 255) ? result : 255;
184
173
WRITE8_HANDLER( exidy440_spriteram_w )
186
space->machine->primary_screen->update_partial(space->machine->primary_screen->vpos());
187
space->machine->generic.spriteram.u8[offset] = data;
175
exidy440_state *state = space->machine().driver_data<exidy440_state>();
176
space->machine().primary_screen->update_partial(space->machine().primary_screen->vpos());
177
state->m_spriteram[offset] = data;
198
188
WRITE8_HANDLER( exidy440_control_w )
200
int oldvis = palettebank_vis;
190
exidy440_state *state = space->machine().driver_data<exidy440_state>();
191
int oldvis = state->m_palettebank_vis;
202
193
/* extract the various bits */
203
exidy440_bank_select(space->machine, data >> 4);
204
firq_enable = (data >> 3) & 1;
205
firq_select = (data >> 2) & 1;
206
palettebank_io = (data >> 1) & 1;
207
palettebank_vis = data & 1;
194
exidy440_bank_select(space->machine(), data >> 4);
195
state->m_firq_enable = (data >> 3) & 1;
196
state->m_firq_select = (data >> 2) & 1;
197
state->m_palettebank_io = (data >> 1) & 1;
198
state->m_palettebank_vis = data & 1;
209
200
/* update the FIRQ in case we enabled something */
210
exidy440_update_firq(space->machine);
201
exidy440_update_firq(space->machine());
212
203
/* if we're swapping palettes, change all the colors */
213
if (oldvis != palettebank_vis)
204
if (oldvis != state->m_palettebank_vis)
217
208
/* pick colors from the visible bank */
218
offset = palettebank_vis * 512;
209
offset = state->m_palettebank_vis * 512;
219
210
for (i = 0; i < 256; i++, offset += 2)
221
212
/* extract a word and the 5-5-5 RGB components */
222
int word = (local_paletteram[offset] << 8) + local_paletteram[offset + 1];
223
palette_set_color_rgb(space->machine, i, pal5bit(word >> 10), pal5bit(word >> 5), pal5bit(word >> 0));
213
int word = (state->m_local_paletteram[offset] << 8) + state->m_local_paletteram[offset + 1];
214
palette_set_color_rgb(space->machine(), i, pal5bit(word >> 10), pal5bit(word >> 5), pal5bit(word >> 0));
229
220
WRITE8_HANDLER( exidy440_interrupt_clear_w )
222
exidy440_state *state = space->machine().driver_data<exidy440_state>();
231
223
/* clear the VBLANK FIRQ on a write here */
232
exidy440_firq_vblank = 0;
233
exidy440_update_firq(space->machine);
224
state->m_firq_vblank = 0;
225
exidy440_update_firq(space->machine());
242
234
*************************************/
244
static void exidy440_update_firq(running_machine *machine)
236
static void exidy440_update_firq(running_machine &machine)
246
if (exidy440_firq_vblank || (firq_enable && exidy440_firq_beam))
238
exidy440_state *state = machine.driver_data<exidy440_state>();
239
if (state->m_firq_vblank || (state->m_firq_enable && state->m_firq_beam))
247
240
cputag_set_input_line(machine, "maincpu", 1, ASSERT_LINE);
249
242
cputag_set_input_line(machine, "maincpu", 1, CLEAR_LINE);
253
246
INTERRUPT_GEN( exidy440_vblank_interrupt )
248
exidy440_state *state = device->machine().driver_data<exidy440_state>();
255
249
/* set the FIRQ line on a VBLANK */
256
exidy440_firq_vblank = 1;
257
exidy440_update_firq(device->machine);
250
state->m_firq_vblank = 1;
251
exidy440_update_firq(device->machine());
268
262
static TIMER_CALLBACK( beam_firq_callback )
264
exidy440_state *state = machine.driver_data<exidy440_state>();
270
265
/* generate the interrupt, if we're selected */
271
if (firq_select && firq_enable)
266
if (state->m_firq_select && state->m_firq_enable)
273
exidy440_firq_beam = 1;
268
state->m_firq_beam = 1;
274
269
exidy440_update_firq(machine);
278
273
param = (param + 1) / 2;
280
275
/* latch the x value; this convolution comes from the read routine */
281
exidy440_latched_x = (param + 3) ^ 2;
276
state->m_latched_x = (param + 3) ^ 2;
285
280
static TIMER_CALLBACK( collide_firq_callback )
282
exidy440_state *state = machine.driver_data<exidy440_state>();
287
283
/* generate the interrupt, if we're selected */
288
if (!firq_select && firq_enable)
284
if (!state->m_firq_select && state->m_firq_enable)
290
exidy440_firq_beam = 1;
286
state->m_firq_beam = 1;
291
287
exidy440_update_firq(machine);
309
305
static void draw_sprites(screen_device &screen, bitmap_t *bitmap, const rectangle *cliprect,
310
306
int scroll_offset, int check_collision)
308
exidy440_state *state = screen.machine().driver_data<exidy440_state>();
314
311
/* get a pointer to the palette to look for collision flags */
315
UINT8 *palette = &local_paletteram[palettebank_vis * 512];
312
UINT8 *palette = &state->m_local_paletteram[state->m_palettebank_vis * 512];
318
315
/* draw the sprite images, checking for collisions along the way */
319
UINT8 *sprite = screen.machine->generic.spriteram.u8 + (SPRITE_COUNT - 1) * 4;
316
UINT8 *sprite = state->m_spriteram + (SPRITE_COUNT - 1) * 4;
321
318
for (i = 0; i < SPRITE_COUNT; i++, sprite -= 4)
375
372
/* check the collisions bit */
376
373
if (check_collision && (palette[2 * pen] & 0x80) && (count++ < 128))
377
timer_set(screen.machine, screen.time_until_pos(yoffs, currx), NULL, currx, collide_firq_callback);
374
screen.machine().scheduler().timer_set(screen.time_until_pos(yoffs, currx), FUNC(collide_firq_callback), currx);
388
385
/* check the collisions bit */
389
386
if (check_collision && (palette[2 * pen] & 0x80) && (count++ < 128))
390
timer_set(screen.machine, screen.time_until_pos(yoffs, currx), NULL, currx, collide_firq_callback);
387
screen.machine().scheduler().timer_set(screen.time_until_pos(yoffs, currx), FUNC(collide_firq_callback), currx);
409
406
static void update_screen(screen_device &screen, bitmap_t *bitmap, const rectangle *cliprect,
410
407
int scroll_offset, int check_collision)
409
exidy440_state *state = screen.machine().driver_data<exidy440_state>();
414
412
/* draw any dirty scanlines from the VRAM directly */
420
418
sy -= (VBSTART - VBEND);
423
draw_scanline8(bitmap, 0, y, (HBSTART - HBEND), &local_videoram[sy * 512], NULL);
421
draw_scanline8(bitmap, 0, y, (HBSTART - HBEND), &state->m_local_videoram[sy * 512], NULL);
426
424
/* draw the sprites */
436
434
*************************************/
438
static VIDEO_UPDATE( exidy440 )
436
static SCREEN_UPDATE( exidy440 )
440
438
/* redraw the screen */
441
439
update_screen(*screen, bitmap, cliprect, 0, TRUE);
448
int beamx = ((input_port_read(screen->machine, "AN0") & 0xff) * (HBSTART - HBEND)) >> 8;
449
int beamy = ((input_port_read(screen->machine, "AN1") & 0xff) * (VBSTART - VBEND)) >> 8;
446
int beamx = ((input_port_read(screen->machine(), "AN0") & 0xff) * (HBSTART - HBEND)) >> 8;
447
int beamy = ((input_port_read(screen->machine(), "AN1") & 0xff) * (VBSTART - VBEND)) >> 8;
451
449
/* The timing of this FIRQ is very important. The games look for an FIRQ
452
450
and then wait about 650 cycles, clear the old FIRQ, and wait a
454
452
From this, it appears that they are expecting to get beams over
455
453
a 12 scanline period, and trying to pick roughly the middle one.
456
454
This is how it is implemented. */
457
attoseconds_t increment = attotime_to_attoseconds(screen->scan_period());
458
attotime time = attotime_sub(screen->time_until_pos(beamy, beamx), attotime_make(0, increment * 6));
455
attotime increment = screen->scan_period();
456
attotime time = screen->time_until_pos(beamy, beamx) - increment * 6;
459
457
for (i = 0; i <= 12; i++)
461
timer_set(screen->machine, time, NULL, beamx, beam_firq_callback);
462
time = attotime_add(time, attotime_make(0, increment));
459
screen->machine().scheduler().timer_set(time, FUNC(beam_firq_callback), beamx);
470
static VIDEO_UPDATE( topsecex )
468
static SCREEN_UPDATE( topsecex )
470
exidy440_state *state = screen->machine().driver_data<exidy440_state>();
472
471
/* redraw the screen */
473
update_screen(*screen, bitmap, cliprect, *topsecex_yscroll, FALSE);
472
update_screen(*screen, bitmap, cliprect, *state->m_topsecex_yscroll, FALSE);
486
485
MACHINE_CONFIG_FRAGMENT( exidy440_video )
487
486
MCFG_VIDEO_ATTRIBUTES(VIDEO_ALWAYS_UPDATE)
488
487
MCFG_VIDEO_START(exidy440)
489
MCFG_VIDEO_UPDATE(exidy440)
490
488
MCFG_PALETTE_LENGTH(256)
492
490
MCFG_SCREEN_ADD("screen", RASTER)
493
491
MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
494
492
MCFG_SCREEN_RAW_PARAMS(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, VTOTAL, VBEND, VBSTART)
493
MCFG_SCREEN_UPDATE(exidy440)
495
494
MACHINE_CONFIG_END
498
497
MACHINE_CONFIG_FRAGMENT( topsecex_video )
499
498
MCFG_VIDEO_ATTRIBUTES(0)
500
499
MCFG_VIDEO_START(topsecex)
501
MCFG_VIDEO_UPDATE(topsecex)
503
501
MCFG_SCREEN_MODIFY("screen")
504
502
MCFG_SCREEN_RAW_PARAMS(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, VTOTAL, VBEND, TOPSECEX_VBSTART)
503
MCFG_SCREEN_UPDATE(topsecex)
505
504
MACHINE_CONFIG_END