~ubuntu-branches/ubuntu/raring/mame/raring-proposed

« back to all changes in this revision

Viewing changes to mess/src/mame/video/williams.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach, Jordi Mallach, Emmanuel Kasper
  • Date: 2011-12-19 22:56:27 UTC
  • mfrom: (0.1.2)
  • Revision ID: package-import@ubuntu.com-20111219225627-ub5oga1oys4ogqzm
Tags: 0.144-1
[ Jordi Mallach ]
* Fix syntax errors in DEP5 copyright file (lintian).
* Use a versioned copyright Format specification field.
* Update Vcs-* URLs.
* Move transitional packages to the new metapackages section, and make
  them priority extra.
* Remove references to GNU/Linux and MESS sources from copyright.
* Add build variables for s390x.
* Use .xz tarballs as it cuts 4MB for the upstream sources.
* Add nplayers.ini as a patch. Update copyright file to add CC-BY-SA-3.0.

[ Emmanuel Kasper ]
* New upstream release. Closes: #651538.
* Add Free Desktop compliant png icons of various sizes taken from
  the hydroxygen iconset
* Mess is now built from a new source package, to avoid possible source
  incompatibilities between mame and the mess overlay.
* Mame-tools are not built from the mame source package anymore, but
  from the mess source package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 
3
 
    Williams 6809 system
4
 
 
5
 
****************************************************************************
6
 
 
7
 
    The basic video system involves a 4-bit-per-pixel bitmap, oriented
8
 
    in inverted X/Y order. That is, pixels (0,0) and (1,0) come from the
9
 
    byte at offset 0. Pixels (2,0) and (3,0) come from the byte at offset
10
 
    256. Pixels (4,0) and (5,0) come from the byte at offset 512. Etc.
11
 
 
12
 
    Defender and Stargate simply draw graphics to the framebuffer directly
13
 
    with no extra intervention.
14
 
 
15
 
    Later games added a pair of "special chips" (SC-01) to the board which
16
 
    are special purpose blitters. During their operation they HALT the
17
 
    main CPU so that they can control the busses. The operation of the
18
 
    chips is described in detail below.
19
 
 
20
 
    The original SC-01 had a bug that forced an XOR of the width and height
21
 
    values with 4. This was fixed in the SC-02, which was used on  several
22
 
    later games.
23
 
 
24
 
    Beginning with Sinistar, additional video tweaks were added.
25
 
 
26
 
    In Sinistar, a clipping window can be specified and enabled in order
27
 
    to prevent the blitter chip from drawing beyond a certain address.
28
 
    This clipping window can be switched on and off at will.
29
 
 
30
 
    In Blaster, a number of features were added. First, a fixed window can
31
 
    be enabled which cuts off blitter drawing at 0x9700. Second, on a
32
 
    per-scanline basis, an "erase behind" feature can be turned on which
33
 
    clears the video RAM to 0 after it is refreshed to the screen. Third,
34
 
    on a per-scanline basis, an alternate color can be latched as the new
35
 
    background color.
36
 
 
37
 
    For Mystic Marathon and the 3 other "2nd generation" Williams games,
38
 
    a tilemap background layer was added. This layer consisted of 24x16
39
 
    tiles and only scrolled in the X direction. In addition, the palette
40
 
    was expanded to 1024 entries, some of which were used for the tilemap.
41
 
    The traditional foreground bitmap could be configured to use any bank
42
 
    of 16 colors from the full palette.
43
 
 
44
 
****************************************************************************
45
 
 
46
 
    Blitter description from Sean Riddle's page:
47
 
 
48
 
    This page contains information about the Williams Special Chips, which
49
 
    were 'bit blitters'- block transfer chips that could move data around on
50
 
    the screen and in memory faster than the CPU. In fact, I've timed the
51
 
    special chips at 16 megs in 18.1 seconds. That's 910K/sec, not bad for
52
 
    the early 80s.
53
 
 
54
 
    The blitters were not used in Defender and Stargate, but
55
 
    were added to the ROM boards of the later games. Splat!, Blaster, Mystic
56
 
    Marathon and Joust 2 used Special Chip 2s. The only difference that I've
57
 
    seen is that SC1s have a small bug. When you tell the SC1 the size of
58
 
    the data to move, you have to exclusive-or the width and height with 2.
59
 
    The SC2s eliminate this bug.
60
 
 
61
 
    The blitters were accessed at memory location $CA00-CA06.
62
 
 
63
 
    CA01 is the mask, usually $FF to move all bits.
64
 
    CA02-3 is the source data location.
65
 
    CA04-5 is the destination data location.
66
 
 
67
 
    Writing to CA00 starts the blit, and the byte written determines how the
68
 
    data is blitted.
69
 
 
70
 
    Bit 0 indicates that the source data is either laid out linear, one
71
 
    pixel after the last, or in screen format, where there are 256 bytes from
72
 
    one pair of pixels to the next.
73
 
 
74
 
    Bit 1 indicates the same, but for the destination data.
75
 
 
76
 
    I'm not sure what bit 2 does. Looking at the image, I can't tell, but
77
 
    perhaps it has to do with the mask. My test files only used a mask of $FF.
78
 
 
79
 
    Bit 3 tells the blitter only to blit the foreground- that is, everything
80
 
    that is not color 0. Also known as transparency mode.
81
 
 
82
 
    Bit 4 is 'solid' mode. Only the color indicated by the mask is blitted.
83
 
    Note that this just creates a rectangle unless bit 3 is also set, in which
84
 
    case it blits the image, but in a solid color.
85
 
 
86
 
    Bit 5 shifts the image one pixel to the right. Any data on the far right
87
 
    jumps to the far left.
88
 
 
89
 
    Bits 6 and 7 only blit every other pixel of the image. Bit 6 says even only,
90
 
    while bit 7 says odd only.
91
 
 
92
 
***************************************************************************/
93
 
 
94
 
#include "emu.h"
95
 
#include "video/resnet.h"
96
 
#include "includes/williams.h"
97
 
 
98
 
 
99
 
 
100
 
/*************************************
101
 
 *
102
 
 *  Prototypes
103
 
 *
104
 
 *************************************/
105
 
 
106
 
static void blitter_init(running_machine &machine, int blitter_config, const UINT8 *remap_prom);
107
 
static void create_palette_lookup(running_machine &machine);
108
 
static TILE_GET_INFO( get_tile_info );
109
 
static int blitter_core(address_space *space, int sstart, int dstart, int w, int h, int data);
110
 
 
111
 
 
112
 
 
113
 
/*************************************
114
 
 *
115
 
 *  Williams video startup
116
 
 *
117
 
 *************************************/
118
 
 
119
 
static void state_save_register(running_machine &machine)
120
 
{
121
 
        williams_state *state = machine.driver_data<williams_state>();
122
 
        state_save_register_global(machine, state->m_blitter_window_enable);
123
 
        state_save_register_global(machine, state->m_cocktail);
124
 
        state_save_register_global_array(machine, state->m_blitterram);
125
 
        state_save_register_global(machine, state->m_blitter_remap_index);
126
 
        state_save_register_global(machine, state->m_blaster_color0);
127
 
        state_save_register_global(machine, state->m_blaster_video_control);
128
 
        state_save_register_global(machine, state->m_tilemap_xscroll);
129
 
        state_save_register_global(machine, state->m_williams2_fg_color);
130
 
}
131
 
 
132
 
 
133
 
VIDEO_START( williams )
134
 
{
135
 
        williams_state *state = machine.driver_data<williams_state>();
136
 
        blitter_init(machine, state->m_blitter_config, NULL);
137
 
        create_palette_lookup(machine);
138
 
        state_save_register(machine);
139
 
}
140
 
 
141
 
 
142
 
VIDEO_START( blaster )
143
 
{
144
 
        williams_state *state = machine.driver_data<williams_state>();
145
 
        blitter_init(machine, state->m_blitter_config, machine.region("proms")->base());
146
 
        create_palette_lookup(machine);
147
 
        state_save_register(machine);
148
 
}
149
 
 
150
 
 
151
 
VIDEO_START( williams2 )
152
 
{
153
 
        williams_state *state = machine.driver_data<williams_state>();
154
 
        blitter_init(machine, state->m_blitter_config, NULL);
155
 
 
156
 
        /* allocate paletteram */
157
 
        machine.generic.paletteram.u8 = auto_alloc_array(machine, UINT8, 0x400 * 2);
158
 
        state_save_register_global_pointer(machine, machine.generic.paletteram.u8, 0x400 * 2);
159
 
 
160
 
        /* create the tilemap */
161
 
        state->m_bg_tilemap = tilemap_create(machine, get_tile_info, tilemap_scan_cols,  24,16, 128,16);
162
 
        tilemap_set_scrolldx(state->m_bg_tilemap, 2, 0);
163
 
 
164
 
        state_save_register(machine);
165
 
}
166
 
 
167
 
 
168
 
 
169
 
/*************************************
170
 
 *
171
 
 *  Williams video update
172
 
 *
173
 
 *************************************/
174
 
 
175
 
SCREEN_UPDATE( williams )
176
 
{
177
 
        williams_state *state = screen->machine().driver_data<williams_state>();
178
 
        rgb_t pens[16];
179
 
        int x, y;
180
 
 
181
 
        /* precompute the palette */
182
 
        for (x = 0; x < 16; x++)
183
 
                pens[x] = state->m_palette_lookup[screen->machine().generic.paletteram.u8[x]];
184
 
 
185
 
        /* loop over rows */
186
 
        for (y = cliprect->min_y; y <= cliprect->max_y; y++)
187
 
        {
188
 
                UINT8 *source = &state->m_videoram[y];
189
 
                UINT32 *dest = BITMAP_ADDR32(bitmap, y, 0);
190
 
 
191
 
                /* loop over columns */
192
 
                for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
193
 
                {
194
 
                        int pix = source[(x/2) * 256];
195
 
                        dest[x+0] = pens[pix >> 4];
196
 
                        dest[x+1] = pens[pix & 0x0f];
197
 
                }
198
 
        }
199
 
        return 0;
200
 
}
201
 
 
202
 
 
203
 
SCREEN_UPDATE( blaster )
204
 
{
205
 
        williams_state *state = screen->machine().driver_data<williams_state>();
206
 
        rgb_t pens[16];
207
 
        int x, y;
208
 
 
209
 
        /* precompute the palette */
210
 
        for (x = 0; x < 16; x++)
211
 
                pens[x] = state->m_palette_lookup[screen->machine().generic.paletteram.u8[x]];
212
 
 
213
 
        /* if we're blitting from the top, start with a 0 for color 0 */
214
 
        if (cliprect->min_y == screen->visible_area().min_y || !(state->m_blaster_video_control & 1))
215
 
                state->m_blaster_color0 = pens[0];
216
 
 
217
 
        /* loop over rows */
218
 
        for (y = cliprect->min_y; y <= cliprect->max_y; y++)
219
 
        {
220
 
                int erase_behind = state->m_blaster_video_control & state->m_blaster_scanline_control[y] & 2;
221
 
                UINT8 *source = &state->m_videoram[y];
222
 
                UINT32 *dest = BITMAP_ADDR32(bitmap, y, 0);
223
 
 
224
 
                /* latch a new color0 pen? */
225
 
                if (state->m_blaster_video_control & state->m_blaster_scanline_control[y] & 1)
226
 
                        state->m_blaster_color0 = state->m_palette_lookup[state->m_blaster_palette_0[y] ^ 0xff];
227
 
 
228
 
                /* loop over columns */
229
 
                for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
230
 
                {
231
 
                        int pix = source[(x/2) * 256];
232
 
 
233
 
                        /* clear behind us if requested */
234
 
                        if (erase_behind)
235
 
                                source[(x/2) * 256] = 0;
236
 
 
237
 
                        /* now draw */
238
 
                        dest[x+0] = (pix & 0xf0) ? pens[pix >> 4] : state->m_blaster_color0;
239
 
                        dest[x+1] = (pix & 0x0f) ? pens[pix & 0x0f] : state->m_blaster_color0;
240
 
                }
241
 
        }
242
 
        return 0;
243
 
}
244
 
 
245
 
 
246
 
SCREEN_UPDATE( williams2 )
247
 
{
248
 
        williams_state *state = screen->machine().driver_data<williams_state>();
249
 
        rgb_t pens[16];
250
 
        int x, y;
251
 
 
252
 
        /* draw the background */
253
 
        tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 0, 0);
254
 
 
255
 
        /* fetch the relevant pens */
256
 
        for (x = 1; x < 16; x++)
257
 
                pens[x] = palette_get_color(screen->machine(), state->m_williams2_fg_color * 16 + x);
258
 
 
259
 
        /* loop over rows */
260
 
        for (y = cliprect->min_y; y <= cliprect->max_y; y++)
261
 
        {
262
 
                UINT8 *source = &state->m_videoram[y];
263
 
                UINT32 *dest = BITMAP_ADDR32(bitmap, y, 0);
264
 
 
265
 
                /* loop over columns */
266
 
                for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
267
 
                {
268
 
                        int pix = source[(x/2) * 256];
269
 
 
270
 
                        if (pix & 0xf0)
271
 
                                dest[x+0] = pens[pix >> 4];
272
 
                        if (pix & 0x0f)
273
 
                                dest[x+1] = pens[pix & 0x0f];
274
 
                }
275
 
        }
276
 
        return 0;
277
 
}
278
 
 
279
 
 
280
 
 
281
 
/*************************************
282
 
 *
283
 
 *  Williams palette I/O
284
 
 *
285
 
 *************************************/
286
 
 
287
 
static void create_palette_lookup(running_machine &machine)
288
 
{
289
 
        williams_state *state = machine.driver_data<williams_state>();
290
 
        static const int resistances_rg[3] = { 1200, 560, 330 };
291
 
        static const int resistances_b[2]  = { 560, 330 };
292
 
        double weights_r[3], weights_g[3], weights_b[2];
293
 
        int i;
294
 
 
295
 
        /* compute palette information */
296
 
        /* note that there really are pullup/pulldown resistors, but this situation is complicated */
297
 
        /* by the use of transistors, so we ignore that and just use the realtive resistor weights */
298
 
        compute_resistor_weights(0,     255, -1.0,
299
 
                        3, resistances_rg, weights_r, 0, 0,
300
 
                        3, resistances_rg, weights_g, 0, 0,
301
 
                        2, resistances_b,  weights_b, 0, 0);
302
 
 
303
 
        /* build a palette lookup */
304
 
        state->m_palette_lookup = auto_alloc_array(machine, rgb_t, 256);
305
 
        for (i = 0; i < 256; i++)
306
 
        {
307
 
                int r = combine_3_weights(weights_r, BIT(i,0), BIT(i,1), BIT(i,2));
308
 
                int g = combine_3_weights(weights_g, BIT(i,3), BIT(i,4), BIT(i,5));
309
 
                int b = combine_2_weights(weights_b, BIT(i,6), BIT(i,7));
310
 
 
311
 
                state->m_palette_lookup[i] = MAKE_RGB(r, g, b);
312
 
        }
313
 
}
314
 
 
315
 
 
316
 
WRITE8_HANDLER( williams2_paletteram_w )
317
 
{
318
 
        static const UINT8 ztable[16] =
319
 
        {
320
 
                0x0, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,  0x9,
321
 
                0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11
322
 
        };
323
 
        UINT8 entry_lo, entry_hi, i, r, g, b;
324
 
 
325
 
        /* set the new value */
326
 
        space->machine().generic.paletteram.u8[offset] = data;
327
 
 
328
 
        /* pull the associated low/high bytes */
329
 
        entry_lo = space->machine().generic.paletteram.u8[offset & ~1];
330
 
        entry_hi = space->machine().generic.paletteram.u8[offset |  1];
331
 
 
332
 
        /* update the palette entry */
333
 
        i = ztable[(entry_hi >> 4) & 15];
334
 
        b = ((entry_hi >> 0) & 15) * i;
335
 
        g = ((entry_lo >> 4) & 15) * i;
336
 
        r = ((entry_lo >> 0) & 15) * i;
337
 
        palette_set_color(space->machine(), offset / 2, MAKE_RGB(r, g, b));
338
 
}
339
 
 
340
 
 
341
 
WRITE8_HANDLER( williams2_fg_select_w )
342
 
{
343
 
        williams_state *state = space->machine().driver_data<williams_state>();
344
 
        state->m_williams2_fg_color = data & 0x3f;
345
 
}
346
 
 
347
 
 
348
 
 
349
 
/*************************************
350
 
 *
351
 
 *  Video position readout
352
 
 *
353
 
 *************************************/
354
 
 
355
 
READ8_HANDLER( williams_video_counter_r )
356
 
{
357
 
        return space->machine().primary_screen->vpos() & 0xfc;
358
 
}
359
 
 
360
 
 
361
 
READ8_HANDLER( williams2_video_counter_r )
362
 
{
363
 
        return space->machine().primary_screen->vpos();
364
 
}
365
 
 
366
 
 
367
 
 
368
 
/*************************************
369
 
 *
370
 
 *  Tilemap handling
371
 
 *
372
 
 *************************************/
373
 
 
374
 
static TILE_GET_INFO( get_tile_info )
375
 
{
376
 
        williams_state *state = machine.driver_data<williams_state>();
377
 
        int mask = machine.gfx[0]->total_elements - 1;
378
 
        int data = state->m_williams2_tileram[tile_index];
379
 
        int y = (tile_index >> 1) & 7;
380
 
        int color = 0;
381
 
 
382
 
        switch (state->m_williams2_tilemap_config)
383
 
        {
384
 
                case WILLIAMS_TILEMAP_MYSTICM:
385
 
                {
386
 
                        /* IC79 is a 74LS85 comparator that controls the low bit */
387
 
                        int a = 1 | ((color & 1) << 2) | ((color & 1) << 3);
388
 
                        int b = ((y & 6) >> 1);
389
 
                        int casc = (y & 1);
390
 
                        color = (a > b) || ((a == b) && !casc);
391
 
                        break;
392
 
                }
393
 
 
394
 
                case WILLIAMS_TILEMAP_TSHOOT:
395
 
                        /* IC79 is a 74LS157 selector jumpered to be enabled */
396
 
                        color = y;
397
 
                        break;
398
 
 
399
 
                case WILLIAMS_TILEMAP_JOUST2:
400
 
                        /* IC79 is a 74LS157 selector jumpered to be disabled */
401
 
                        color = 0;
402
 
                        break;
403
 
        }
404
 
 
405
 
        SET_TILE_INFO(0, data & mask, color, (data & ~mask) ? TILE_FLIPX : 0);
406
 
}
407
 
 
408
 
 
409
 
WRITE8_HANDLER( williams2_bg_select_w )
410
 
{
411
 
        williams_state *state = space->machine().driver_data<williams_state>();
412
 
        /* based on the tilemap config, only certain bits are used */
413
 
        /* the rest are determined by other factors */
414
 
        switch (state->m_williams2_tilemap_config)
415
 
        {
416
 
                case WILLIAMS_TILEMAP_MYSTICM:
417
 
                        /* IC79 is a 74LS85 comparator that controls the low bit */
418
 
                        data &= 0x3e;
419
 
                        break;
420
 
 
421
 
                case WILLIAMS_TILEMAP_TSHOOT:
422
 
                        /* IC79 is a 74LS157 selector jumpered to be enabled */
423
 
                        data &= 0x38;
424
 
                        break;
425
 
 
426
 
                case WILLIAMS_TILEMAP_JOUST2:
427
 
                        /* IC79 is a 74LS157 selector jumpered to be disabled */
428
 
                        data &= 0x3f;
429
 
                        break;
430
 
        }
431
 
        tilemap_set_palette_offset(state->m_bg_tilemap, data * 16);
432
 
}
433
 
 
434
 
 
435
 
WRITE8_HANDLER( williams2_tileram_w )
436
 
{
437
 
        williams_state *state = space->machine().driver_data<williams_state>();
438
 
        state->m_williams2_tileram[offset] = data;
439
 
        tilemap_mark_tile_dirty(state->m_bg_tilemap, offset);
440
 
}
441
 
 
442
 
 
443
 
WRITE8_HANDLER( williams2_xscroll_low_w )
444
 
{
445
 
        williams_state *state = space->machine().driver_data<williams_state>();
446
 
        state->m_tilemap_xscroll = (state->m_tilemap_xscroll & ~0x00f) | ((data & 0x80) >> 4) | (data & 0x07);
447
 
        tilemap_set_scrollx(state->m_bg_tilemap, 0, (state->m_tilemap_xscroll & 7) + ((state->m_tilemap_xscroll >> 3) * 6));
448
 
}
449
 
 
450
 
 
451
 
WRITE8_HANDLER( williams2_xscroll_high_w )
452
 
{
453
 
        williams_state *state = space->machine().driver_data<williams_state>();
454
 
        state->m_tilemap_xscroll = (state->m_tilemap_xscroll & 0x00f) | (data << 4);
455
 
        tilemap_set_scrollx(state->m_bg_tilemap, 0, (state->m_tilemap_xscroll & 7) + ((state->m_tilemap_xscroll >> 3) * 6));
456
 
}
457
 
 
458
 
 
459
 
 
460
 
/*************************************
461
 
 *
462
 
 *  Blaster-specific enhancements
463
 
 *
464
 
 *************************************/
465
 
 
466
 
WRITE8_HANDLER( blaster_remap_select_w )
467
 
{
468
 
        williams_state *state = space->machine().driver_data<williams_state>();
469
 
        state->m_blitter_remap_index = data;
470
 
        state->m_blitter_remap = state->m_blitter_remap_lookup + data * 256;
471
 
}
472
 
 
473
 
 
474
 
WRITE8_HANDLER( blaster_video_control_w )
475
 
{
476
 
        williams_state *state = space->machine().driver_data<williams_state>();
477
 
        state->m_blaster_video_control = data;
478
 
}
479
 
 
480
 
 
481
 
 
482
 
/*************************************
483
 
 *
484
 
 *  Blitter setup and control
485
 
 *
486
 
 *************************************/
487
 
 
488
 
static void blitter_init(running_machine &machine, int blitter_config, const UINT8 *remap_prom)
489
 
{
490
 
        williams_state *state = machine.driver_data<williams_state>();
491
 
        static const UINT8 dummy_table[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
492
 
        int i,j;
493
 
 
494
 
        /* by default, there is no clipping window - this will be touched only by games that have one */
495
 
        state->m_blitter_window_enable = 0;
496
 
 
497
 
        /* switch off the video config */
498
 
        state->m_blitter_xor = (blitter_config == WILLIAMS_BLITTER_SC01) ? 4 : 0;
499
 
 
500
 
        /* create the remap table; if no PROM, make an identity remap table */
501
 
        state->m_blitter_remap_lookup = auto_alloc_array(machine, UINT8, 256 * 256);
502
 
        state->m_blitter_remap_index = 0;
503
 
        state->m_blitter_remap = state->m_blitter_remap_lookup;
504
 
        for (i = 0; i < 256; i++)
505
 
        {
506
 
                const UINT8 *table = remap_prom ? (remap_prom + (i & 0x7f) * 16) : dummy_table;
507
 
                for (j = 0; j < 256; j++)
508
 
                        state->m_blitter_remap_lookup[i * 256 + j] = (table[j >> 4] << 4) | table[j & 0x0f];
509
 
        }
510
 
}
511
 
 
512
 
 
513
 
WRITE8_HANDLER( williams_blitter_w )
514
 
{
515
 
        williams_state *state = space->machine().driver_data<williams_state>();
516
 
        int sstart, dstart, w, h, accesses;
517
 
        int estimated_clocks_at_4MHz;
518
 
 
519
 
        /* store the data */
520
 
        state->m_blitterram[offset] = data;
521
 
 
522
 
        /* only writes to location 0 trigger the blit */
523
 
        if (offset != 0)
524
 
                return;
525
 
 
526
 
        /* compute the starting locations */
527
 
        sstart = (state->m_blitterram[2] << 8) + state->m_blitterram[3];
528
 
        dstart = (state->m_blitterram[4] << 8) + state->m_blitterram[5];
529
 
 
530
 
        /* compute the width and height */
531
 
        w = state->m_blitterram[6] ^ state->m_blitter_xor;
532
 
        h = state->m_blitterram[7] ^ state->m_blitter_xor;
533
 
 
534
 
        /* adjust the width and height */
535
 
        if (w == 0) w = 1;
536
 
        if (h == 0) h = 1;
537
 
        if (w == 255) w = 256;
538
 
        if (h == 255) h = 256;
539
 
 
540
 
        /* do the actual blit */
541
 
        accesses = blitter_core(space, sstart, dstart, w, h, data);
542
 
 
543
 
        /* based on the number of memory accesses needed to do the blit, compute how long the blit will take */
544
 
        /* this is just a guess */
545
 
        estimated_clocks_at_4MHz = 20 + 2 * accesses;
546
 
        device_adjust_icount(&space->device(), -((estimated_clocks_at_4MHz + 3) / 4));
547
 
 
548
 
        /* Log blits */
549
 
        logerror("%04X:Blit @ %3d : %02X%02X -> %02X%02X, %3dx%3d, mask=%02X, flags=%02X, icount=%d, win=%d\n",
550
 
                        cpu_get_pc(&space->device()), space->machine().primary_screen->vpos(),
551
 
                        state->m_blitterram[2], state->m_blitterram[3],
552
 
                        state->m_blitterram[4], state->m_blitterram[5],
553
 
                        state->m_blitterram[6], state->m_blitterram[7],
554
 
                        state->m_blitterram[1], state->m_blitterram[0],
555
 
                        ((estimated_clocks_at_4MHz + 3) / 4), state->m_blitter_window_enable);
556
 
}
557
 
 
558
 
 
559
 
WRITE8_HANDLER( williams2_blit_window_enable_w )
560
 
{
561
 
        williams_state *state = space->machine().driver_data<williams_state>();
562
 
        state->m_blitter_window_enable = data & 0x01;
563
 
}
564
 
 
565
 
 
566
 
 
567
 
/*************************************
568
 
 *
569
 
 *  Blitter core
570
 
 *
571
 
 *************************************/
572
 
 
573
 
INLINE void blit_pixel(address_space *space, int offset, int srcdata, int data, int mask, int solid)
574
 
{
575
 
        williams_state *state = space->machine().driver_data<williams_state>();
576
 
        /* always read from video RAM regardless of the bank setting */
577
 
        int pix = (offset < 0xc000) ? state->m_videoram[offset] : space->read_byte(offset);
578
 
 
579
 
        /* handle transparency */
580
 
        if (data & 0x08)
581
 
        {
582
 
                if (!(srcdata & 0xf0)) mask |= 0xf0;
583
 
                if (!(srcdata & 0x0f)) mask |= 0x0f;
584
 
        }
585
 
 
586
 
        /* handle solid versus source data */
587
 
        pix &= mask;
588
 
        if (data & 0x10)
589
 
                pix |= solid & ~mask;
590
 
        else
591
 
                pix |= srcdata & ~mask;
592
 
 
593
 
        /* if the window is enabled, only blit to videoram below the clipping address */
594
 
        /* note that we have to allow blits to non-video RAM (e.g. tileram) because those */
595
 
        /* are not blocked by the window enable */
596
 
        if (!state->m_blitter_window_enable || offset < state->m_blitter_clip_address || offset >= 0xc000)
597
 
                space->write_byte(offset, pix);
598
 
}
599
 
 
600
 
 
601
 
static int blitter_core(address_space *space, int sstart, int dstart, int w, int h, int data)
602
 
{
603
 
        williams_state *state = space->machine().driver_data<williams_state>();
604
 
        int source, sxadv, syadv;
605
 
        int dest, dxadv, dyadv;
606
 
        int i, j, solid;
607
 
        int accesses = 0;
608
 
        int keepmask;
609
 
 
610
 
        /* compute how much to advance in the x and y loops */
611
 
        sxadv = (data & 0x01) ? 0x100 : 1;
612
 
        syadv = (data & 0x01) ? 1 : w;
613
 
        dxadv = (data & 0x02) ? 0x100 : 1;
614
 
        dyadv = (data & 0x02) ? 1 : w;
615
 
 
616
 
        /* determine the common mask */
617
 
        keepmask = 0x00;
618
 
        if (data & 0x80) keepmask |= 0xf0;
619
 
        if (data & 0x40) keepmask |= 0x0f;
620
 
        if (keepmask == 0xff)
621
 
                return accesses;
622
 
 
623
 
        /* set the solid pixel value to the mask value */
624
 
        solid = state->m_blitterram[1];
625
 
 
626
 
        /* first case: no shifting */
627
 
        if (!(data & 0x20))
628
 
        {
629
 
                /* loop over the height */
630
 
                for (i = 0; i < h; i++)
631
 
                {
632
 
                        source = sstart & 0xffff;
633
 
                        dest = dstart & 0xffff;
634
 
 
635
 
                        /* loop over the width */
636
 
                        for (j = w; j > 0; j--)
637
 
                        {
638
 
                                blit_pixel(space, dest, state->m_blitter_remap[space->read_byte(source)], data, keepmask, solid);
639
 
                                accesses += 2;
640
 
 
641
 
                                /* advance */
642
 
                                source = (source + sxadv) & 0xffff;
643
 
                                dest   = (dest + dxadv) & 0xffff;
644
 
                        }
645
 
 
646
 
                        sstart += syadv;
647
 
 
648
 
                        /* note that PlayBall! indicates the X coordinate doesn't wrap */
649
 
                        if (data & 0x02)
650
 
                                dstart = (dstart & 0xff00) | ((dstart + dyadv) & 0xff);
651
 
                        else
652
 
                                dstart += dyadv;
653
 
                }
654
 
        }
655
 
 
656
 
        /* second case: shifted one pixel */
657
 
        else
658
 
        {
659
 
                /* swap halves of the keep mask and the solid color */
660
 
                keepmask = ((keepmask & 0xf0) >> 4) | ((keepmask & 0x0f) << 4);
661
 
                solid = ((solid & 0xf0) >> 4) | ((solid & 0x0f) << 4);
662
 
 
663
 
                /* loop over the height */
664
 
                for (i = 0; i < h; i++)
665
 
                {
666
 
                        int pixdata;
667
 
 
668
 
                        source = sstart & 0xffff;
669
 
                        dest = dstart & 0xffff;
670
 
 
671
 
                        /* left edge case */
672
 
                        pixdata = state->m_blitter_remap[space->read_byte(source)];
673
 
                        blit_pixel(space, dest, (pixdata >> 4) & 0x0f, data, keepmask | 0xf0, solid);
674
 
                        accesses += 2;
675
 
 
676
 
                        source = (source + sxadv) & 0xffff;
677
 
                        dest   = (dest + dxadv) & 0xffff;
678
 
 
679
 
                        /* loop over the width */
680
 
                        for (j = w - 1; j > 0; j--)
681
 
                        {
682
 
                                pixdata = (pixdata << 8) | state->m_blitter_remap[space->read_byte(source)];
683
 
                                blit_pixel(space, dest, (pixdata >> 4) & 0xff, data, keepmask, solid);
684
 
                                accesses += 2;
685
 
 
686
 
                                source = (source + sxadv) & 0xffff;
687
 
                                dest   = (dest + dxadv) & 0xffff;
688
 
                        }
689
 
 
690
 
                        /* right edge case */
691
 
                        blit_pixel(space, dest, (pixdata << 4) & 0xf0, data, keepmask | 0x0f, solid);
692
 
                        accesses++;
693
 
 
694
 
                        sstart += syadv;
695
 
 
696
 
                        /* note that PlayBall! indicates the X coordinate doesn't wrap */
697
 
                        if (data & 0x02)
698
 
                                dstart = (dstart & 0xff00) | ((dstart + dyadv) & 0xff);
699
 
                        else
700
 
                                dstart += dyadv;
701
 
                }
702
 
        }
703
 
 
704
 
        return accesses;
705
 
}