1 // license:BSD-3-Clause
2 // copyright-holders:Ernesto Corvi, Mariusz Wojcieszek, Aaron Giles
3 /***************************************************************************
4
5 Amiga hardware
6
7 Driver by: Ernesto Corvi, Mariusz Wojcieszek, Aaron Giles
8
9 ***************************************************************************/
10
11 #include "emu.h"
12 #include "includes/amiga.h"
13
14
15
16 /*************************************
17 *
18 * Debugging
19 *
20 *************************************/
21
22 #define LOG_COPPER 0
23 #define GUESS_COPPER_OFFSET 0
24 #define LOG_SPRITE_DMA 0
25
26
27
28 /*************************************
29 *
30 * Macros
31 *
32 *************************************/
33
34 #define COPPER_CYCLES_TO_PIXELS(x) (4 * (x))
35
36
37
38 /*************************************
39 *
40 * Tables
41 *
42 *************************************/
43
44 /* expand an 8-bit bit pattern into 16 bits, every other bit */
45 const uint16_t amiga_state::s_expand_byte[256] =
46 {
47 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
48 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
49 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
50 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
51 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
52 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
53 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
54 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
55 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
56 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
57 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
58 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
59 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
60 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
61 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
62 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
63
64 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
65 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
66 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
67 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
68 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
69 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
70 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
71 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
72 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
73 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
74 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
75 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
76 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
77 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
78 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
79 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
80 };
81
82 const uint16_t delay[256] =
83 {
84 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 0x000 - 0x03e */
85 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x040 - 0x05e */
86 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x060 - 0x07e */
87 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, /* 0x080 - 0x09e */
88 1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0, /* 0x0a0 - 0x0de */
89 /* BPLxPTH/BPLxPTL */
90 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x0e0 - 0x0fe */
91 /* BPLCON0-3,BPLMOD1-2 */
92 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x100 - 0x11e */
93 /* SPRxPTH/SPRxPTL */
94 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x120 - 0x13e */
95 /* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */
96 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x140 - 0x17e */
97 /* COLORxx */
98 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x180 - 0x1be */
99 /* RESERVED */
100 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0x1c0 - 0x1fe */
101 };
102
103
104
105 /*************************************
106 *
107 * 4-4-4 palette init
108 *
109 *************************************/
110
amiga_palette(palette_device & palette) const111 void amiga_state::amiga_palette(palette_device &palette) const
112 {
113 for (int i = 0; i < 0x1000; i++)
114 palette.set_pen_color(i, pal4bit(i >> 8), pal4bit(i >> 4), pal4bit(i));
115 }
116
117
118
119 /*************************************
120 *
121 * Video startup
122 *
123 *************************************/
124
VIDEO_START_MEMBER(amiga_state,amiga)125 VIDEO_START_MEMBER( amiga_state, amiga )
126 {
127 int j;
128
129 /* generate tables that produce the correct playfield color for dual playfield mode */
130 for (j = 0; j < 64; j++)
131 {
132 int pf1pix = ((j >> 0) & 1) | ((j >> 1) & 2) | ((j >> 2) & 4);
133 int pf2pix = ((j >> 1) & 1) | ((j >> 2) & 2) | ((j >> 3) & 4);
134
135 m_separate_bitplanes[0][j] = (pf1pix || !pf2pix) ? pf1pix : (pf2pix + 8);
136 m_separate_bitplanes[1][j] = pf2pix ? (pf2pix + 8) : pf1pix;
137 }
138
139 #if GUESS_COPPER_OFFSET
140 m_wait_offset = 3;
141 #else
142 (void)m_wait_offset;
143 #endif
144
145 /* reset the genlock color */
146 m_genlock_color = 0xffff;
147
148 m_sprite_ctl_written = 0;
149
150 m_screen->register_screen_bitmap(m_flickerfixer);
151 }
152
153
154
155 /*************************************
156 *
157 * Beam position
158 *
159 *************************************/
160
amiga_gethvpos()161 uint32_t amiga_state::amiga_gethvpos()
162 {
163 uint32_t hvpos = (m_last_scanline << 8) | (m_screen->hpos() >> 2);
164 uint32_t latchedpos = m_hvpos.read_safe(0);
165
166 /* if there's no latched position, or if we are in the active display area */
167 /* but before the latching point, return the live HV position */
168 if ((CUSTOM_REG(REG_BPLCON0) & 0x0008) == 0 || latchedpos == 0 || (m_last_scanline >= 20 && hvpos < latchedpos))
169 return hvpos;
170
171 /* otherwise, return the latched position */
172 return latchedpos;
173 }
174
175
176
177 /*************************************
178 *
179 * Genlock interaction
180 *
181 *************************************/
182
set_genlock_color(uint16_t color)183 void amiga_state::set_genlock_color(uint16_t color)
184 {
185 m_genlock_color = color;
186 }
187
188
189
190 /*************************************
191 *
192 * Copper emulation
193 *
194 *************************************/
195
copper_setpc(uint32_t pc)196 void amiga_state::copper_setpc(uint32_t pc)
197 {
198 if (LOG_COPPER)
199 logerror("copper_setpc(%06x)\n", pc);
200
201 m_copper_pc = pc;
202 m_copper_waiting = false;
203 }
204
205
copper_execute_next(int xpos)206 int amiga_state::copper_execute_next(int xpos)
207 {
208 uint8_t ypos = m_last_scanline & 0xff;
209 int word0, word1;
210
211 /* bail if not enabled */
212 if ((CUSTOM_REG(REG_DMACON) & (DMACON_COPEN | DMACON_DMAEN)) != (DMACON_COPEN | DMACON_DMAEN))
213 return 511;
214
215 /* flush any pending writes */
216 if (m_copper_pending_offset)
217 {
218 if (LOG_COPPER)
219 logerror("%02X.%02X: Write to %s = %04x\n", m_last_scanline, xpos / 2, s_custom_reg_names[m_copper_pending_offset & 0xff], m_copper_pending_data);
220 custom_chip_w(m_copper_pending_offset, m_copper_pending_data);
221 m_copper_pending_offset = 0;
222 }
223
224 /* if we're waiting, check for a breakthrough */
225 if (m_copper_waiting)
226 {
227 int curpos = (ypos << 8) | (xpos >> 1);
228
229 /* if we're past the wait time, stop it and hold up 2 cycles */
230 if ((curpos & m_copper_waitmask) >= (m_copper_waitval & m_copper_waitmask) &&
231 (!m_copper_waitblit || !(CUSTOM_REG(REG_DMACON) & DMACON_BBUSY)))
232 {
233 m_copper_waiting = false;
234 #if GUESS_COPPER_OFFSET
235 return xpos + COPPER_CYCLES_TO_PIXELS(1 + m_wait_offset);
236 #else
237 return xpos + COPPER_CYCLES_TO_PIXELS(1 + 3);
238 #endif
239 }
240
241 /* otherwise, see if this line is even a possibility; if not, punt */
242 if (((curpos | 0xff) & m_copper_waitmask) < (m_copper_waitval & m_copper_waitmask))
243 return 511;
244
245 /* else just advance another pixel */
246 xpos += COPPER_CYCLES_TO_PIXELS(1);
247 return xpos;
248 }
249
250 /* fetch the first data word */
251 word0 = read_chip_ram(m_copper_pc);
252 m_copper_pc += 2;
253 xpos += COPPER_CYCLES_TO_PIXELS(1);
254
255 /* fetch the second data word */
256 word1 = read_chip_ram(m_copper_pc);
257 m_copper_pc += 2;
258 xpos += COPPER_CYCLES_TO_PIXELS(1);
259
260 if (LOG_COPPER)
261 logerror("%02X.%02X: Copper inst @ %06x = %04x %04x\n", m_last_scanline, xpos / 2, m_copper_pc, word0, word1);
262
263 /* handle a move */
264 if ((word0 & 1) == 0)
265 {
266 int min = (CUSTOM_REG(REG_COPCON) & 2) ? 0x20 : 0x40;
267
268 /* do the write if we're allowed */
269 word0 = (word0 >> 1) & 0xff;
270 if (word0 >= min)
271 {
272 if (delay[word0] == 0)
273 {
274 if (LOG_COPPER)
275 logerror("%02X.%02X: Write to %s = %04x\n", m_last_scanline, xpos / 2, s_custom_reg_names[word0 & 0xff], word1);
276 custom_chip_w(word0, word1);
277 }
278 else // additional 2 cycles needed for non-Agnus registers
279 {
280 m_copper_pending_offset = word0;
281 m_copper_pending_data = word1;
282 }
283 }
284
285 /* illegal writes suspend until next frame */
286 else
287 {
288 if (LOG_COPPER)
289 logerror("%02X.%02X: Aborting copper on illegal write\n", m_last_scanline, xpos / 2);
290
291 m_copper_waitval = 0xffff;
292 m_copper_waitmask = 0xffff;
293 m_copper_waitblit = false;
294 m_copper_waiting = true;
295
296 return 511;
297 }
298 }
299 else
300 {
301 /* extract common wait/skip values */
302 m_copper_waitval = word0 & 0xfffe;
303
304 #if 0
305 if (m_copper_waitval != 0xfffe)
306 m_copper_waitval = (word0 & 0x00fe) | ((((word0 >> 8) & 0xff) + 1) << 8);
307 #endif
308
309 m_copper_waitmask = word1 | 0x8001;
310 m_copper_waitblit = (~word1 >> 15) & 1;
311
312 /* handle a wait */
313 if ((word1 & 1) == 0)
314 {
315 if (LOG_COPPER)
316 logerror(" Waiting for %04x & %04x (currently %04x)\n", m_copper_waitval, m_copper_waitmask, (m_last_scanline << 8) | (xpos >> 1));
317
318 m_copper_waiting = true;
319 }
320
321 /* handle a skip */
322 else
323 {
324 int curpos = (ypos << 8) | (xpos >> 1);
325
326 if (LOG_COPPER)
327 logerror(" Skipping if %04x & %04x (currently %04x)\n", m_copper_waitval, m_copper_waitmask, (m_last_scanline << 8) | (xpos >> 1));
328
329 /* if we're past the wait time, stop it and hold up 2 cycles */
330 if ((curpos & m_copper_waitmask) >= (m_copper_waitval & m_copper_waitmask) &&
331 (!m_copper_waitblit || !(CUSTOM_REG(REG_DMACON) & DMACON_BBUSY)))
332 {
333 if (LOG_COPPER)
334 logerror(" Skipped\n");
335
336 /* count the cycles it out have taken to fetch the next instruction */
337 m_copper_pc += 4;
338 xpos += COPPER_CYCLES_TO_PIXELS(2);
339 }
340 }
341 }
342
343 /* advance and consume 8 cycles */
344 return xpos;
345 }
346
347
348
349 /*************************************
350 *
351 * External sprite controls
352 *
353 *************************************/
354
sprite_dma_reset(int which)355 void amiga_state::sprite_dma_reset(int which)
356 {
357 if (LOG_SPRITE_DMA) logerror("sprite %d dma reset\n", which );
358 m_sprite_dma_reload_mask |= 1 << which;
359 m_sprite_dma_live_mask |= 1 << which;
360 }
361
362
sprite_enable_comparitor(int which,int enable)363 void amiga_state::sprite_enable_comparitor(int which, int enable)
364 {
365 if (LOG_SPRITE_DMA) logerror("sprite %d comparitor %sable\n", which, enable ? "en" : "dis" );
366 if (enable)
367 {
368 m_sprite_comparitor_enable_mask |= 1 << which;
369 m_sprite_dma_live_mask &= ~(1 << which);
370 }
371 else
372 {
373 m_sprite_comparitor_enable_mask &= ~(1 << which);
374 m_sprite_ctl_written |= (1 << which);
375 }
376 }
377
378
379
380 /*************************************
381 *
382 * Per-scanline sprite fetcher
383 *
384 *************************************/
385
fetch_sprite_data(int scanline,int sprite)386 void amiga_state::fetch_sprite_data(int scanline, int sprite)
387 {
388 CUSTOM_REG(REG_SPR0DATA + 4 * sprite) = read_chip_ram(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * sprite) + 0);
389 CUSTOM_REG(REG_SPR0DATB + 4 * sprite) = read_chip_ram(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * sprite) + 2);
390 CUSTOM_REG_LONG(REG_SPR0PTH + 2 * sprite) += 4;
391 if (LOG_SPRITE_DMA) logerror("%3d:sprite %d fetch: data=%04X-%04X\n", scanline, sprite, CUSTOM_REG(REG_SPR0DATA + 4 * sprite), CUSTOM_REG(REG_SPR0DATB + 4 * sprite));
392 }
393
update_sprite_dma(int scanline)394 void amiga_state::update_sprite_dma(int scanline)
395 {
396 int dmaenable = (CUSTOM_REG(REG_DMACON) & (DMACON_SPREN | DMACON_DMAEN)) == (DMACON_SPREN | DMACON_DMAEN);
397 int num, maxdma;
398
399 /* channels are limited by DDFSTART */
400 maxdma = (CUSTOM_REG(REG_DDFSTRT) - 0x14) / 4;
401 if (maxdma > 8)
402 maxdma = 8;
403
404 /* loop over sprite channels */
405 for (num = 0; num < maxdma; num++)
406 {
407 int bitmask = 1 << num;
408 int vstart, vstop;
409
410 /* if we are == VSTOP, fetch new control words */
411 if (dmaenable && (m_sprite_dma_live_mask & bitmask) && (m_sprite_dma_reload_mask & bitmask))
412 {
413 /* disable the sprite */
414 m_sprite_comparitor_enable_mask &= ~bitmask;
415 m_sprite_dma_reload_mask &= ~bitmask;
416
417 /* fetch data into the control words */
418 CUSTOM_REG(REG_SPR0POS + 4 * num) = read_chip_ram(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) + 0);
419 CUSTOM_REG(REG_SPR0CTL + 4 * num) = read_chip_ram(CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) + 2);
420 CUSTOM_REG_LONG(REG_SPR0PTH + 2 * num) += 4;
421 if (LOG_SPRITE_DMA) logerror("%3d:sprite %d fetch: pos=%04X ctl=%04X\n", scanline, num, CUSTOM_REG(REG_SPR0POS + 4 * num), CUSTOM_REG(REG_SPR0CTL + 4 * num));
422 }
423
424 /* compute vstart/vstop */
425 vstart = (CUSTOM_REG(REG_SPR0POS + 4 * num) >> 8) | ((CUSTOM_REG(REG_SPR0CTL + 4 * num) << 6) & 0x100);
426 vstop = (CUSTOM_REG(REG_SPR0CTL + 4 * num) >> 8) | ((CUSTOM_REG(REG_SPR0CTL + 4 * num) << 7) & 0x100);
427
428 /* if we hit vstart, enable the comparitor */
429 if (scanline == vstart)
430 {
431 m_sprite_comparitor_enable_mask |= 1 << num;
432 if (LOG_SPRITE_DMA) logerror("%3d:sprite %d comparitor enable\n", scanline, num);
433 }
434
435 /* if we hit vstop, disable the comparitor and trigger a reload for the next scanline */
436 if (scanline == vstop)
437 {
438 m_sprite_ctl_written &= ~bitmask;
439 m_sprite_comparitor_enable_mask &= ~bitmask;
440 m_sprite_dma_reload_mask |= 1 << num;
441 CUSTOM_REG(REG_SPR0DATA + 4 * num) = 0; /* just a guess */
442 CUSTOM_REG(REG_SPR0DATB + 4 * num) = 0;
443 if (LOG_SPRITE_DMA) logerror("%3d:sprite %d comparitor disable, prepare for reload\n", scanline, num);
444 }
445
446 /* fetch data if this sprite is enabled */
447 if (dmaenable && (m_sprite_dma_live_mask & bitmask) && (m_sprite_comparitor_enable_mask & bitmask))
448 {
449 fetch_sprite_data(scanline, num);
450 }
451 }
452 }
453
454
455
456 /*************************************
457 *
458 * Per-pixel sprite computations
459 *
460 *************************************/
461
interleave_sprite_data(uint16_t lobits,uint16_t hibits)462 uint32_t amiga_state::interleave_sprite_data(uint16_t lobits, uint16_t hibits)
463 {
464 return (s_expand_byte[lobits & 0xff] << 0) | (s_expand_byte[lobits >> 8] << 16) |
465 (s_expand_byte[hibits & 0xff] << 1) | (s_expand_byte[hibits >> 8] << 17);
466 }
467
468
get_sprite_pixel(int x)469 int amiga_state::get_sprite_pixel(int x)
470 {
471 int pixels = 0;
472 int num, pair;
473
474 /* loop over sprite channels */
475 for (num = 0; num < 8; num++)
476 if (m_sprite_comparitor_enable_mask & (1 << num))
477 {
478 /* if we're not currently clocking, check against hstart */
479 if (m_sprite_remain[num] == 0)
480 {
481 int hstart = ((CUSTOM_REG(REG_SPR0POS + 4 * num) & 0xff) << 1) | (CUSTOM_REG(REG_SPR0CTL + 4 * num) & 1);
482 if (hstart == x)
483 {
484 m_sprite_remain[num] = 16;
485 m_sprite_shiftreg[num] = interleave_sprite_data(CUSTOM_REG(REG_SPR0DATA + 4 * num), CUSTOM_REG(REG_SPR0DATB + 4 * num));
486 }
487 }
488
489 /* clock the next pixel if we're doing it */
490 if (m_sprite_remain[num] != 0)
491 {
492 m_sprite_remain[num]--;
493 pixels |= (m_sprite_shiftreg[num] & 0xc0000000) >> (16 + 2 * (7 - num));
494 m_sprite_shiftreg[num] <<= 2;
495 }
496 }
497
498 /* if we have pixels, determine the actual color and get out */
499 if (pixels)
500 {
501 static const uint16_t ormask[16] =
502 {
503 0x0000, 0x000c, 0x00c0, 0x00cc, 0x0c00, 0x0c0c, 0x0cc0, 0x0ccc,
504 0xc000, 0xc00c, 0xc0c0, 0xc0cc, 0xcc00, 0xcc0c, 0xccc0, 0xcccc
505 };
506 static const uint16_t spritecollide[16] =
507 {
508 0x0000, 0x0000, 0x0000, 0x0200, 0x0000, 0x0400, 0x1000, 0x1600,
509 0x0000, 0x0800, 0x2000, 0x2a00, 0x4000, 0x4c00, 0x7000, 0x7e00
510 };
511 int collide;
512 const int esprm = 0x10, osprm = 0x10;
513
514 /* OR the two sprite bits together so we only have 1 bit per sprite */
515 collide = pixels | (pixels >> 1);
516
517 /* based on the CLXCON, merge even/odd sprite results */
518 collide |= (collide & ormask[CUSTOM_REG(REG_CLXCON) >> 12]) >> 2;
519
520 /* collapse down to a 4-bit final "sprite present" mask */
521 collide = (collide & 1) | ((collide >> 3) & 2) | ((collide >> 6) & 4) | ((collide >> 9) & 8);
522
523 /* compute sprite-sprite collisions */
524 CUSTOM_REG(REG_CLXDAT) |= spritecollide[collide];
525
526 /* now determine the actual color */
527 for (pair = 0; pixels; pair++, pixels >>= 4)
528 if (pixels & 0x0f)
529 {
530 /* final result is:
531 topmost sprite color in bits 0-5
532 sprite present bitmask in bits 6-9
533 topmost sprite pair index in bits 10-11
534 */
535 uint32_t result = (collide << 6) | (pair << 10);
536
537 /* attached case */
538 if (CUSTOM_REG(REG_SPR1CTL + 8 * pair) & 0x0080)
539 return (pixels & 0xf) | osprm | result;
540
541 /* lower-numbered sprite of pair */
542 else if (pixels & 3)
543 return (pixels & 3) | esprm | (pair << 2) | result;
544
545 /* higher-numbered sprite of pair */
546 else
547 return ((pixels >> 2) & 3) | osprm | (pair << 2) | result;
548 }
549 }
550
551 return 0;
552 }
553
554
555
556 /*************************************
557 *
558 * Bitplane assembly
559 *
560 *************************************/
561
assemble_odd_bitplanes(int planes,int obitoffs)562 uint8_t amiga_state::assemble_odd_bitplanes(int planes, int obitoffs)
563 {
564 uint8_t pix = (CUSTOM_REG(REG_BPL1DAT) >> obitoffs) & 1;
565 if (planes >= 3)
566 {
567 pix |= ((CUSTOM_REG(REG_BPL3DAT) >> obitoffs) & 1) << 2;
568 if (planes >= 5)
569 pix |= ((CUSTOM_REG(REG_BPL5DAT) >> obitoffs) & 1) << 4;
570 }
571 return pix;
572 }
573
574
assemble_even_bitplanes(int planes,int ebitoffs)575 uint8_t amiga_state::assemble_even_bitplanes(int planes, int ebitoffs)
576 {
577 uint8_t pix = 0;
578 if (planes >= 2)
579 {
580 pix |= ((CUSTOM_REG(REG_BPL2DAT) >> ebitoffs) & 1) << 1;
581 if (planes >= 4)
582 {
583 pix |= ((CUSTOM_REG(REG_BPL4DAT) >> ebitoffs) & 1) << 3;
584 if (planes >= 6)
585 pix |= ((CUSTOM_REG(REG_BPL6DAT) >> ebitoffs) & 1) << 5;
586 }
587 }
588 return pix;
589 }
590
fetch_bitplane_data(int plane)591 void amiga_state::fetch_bitplane_data(int plane)
592 {
593 CUSTOM_REG(REG_BPL1DAT + plane) = read_chip_ram(CUSTOM_REG_LONG(REG_BPL1PTH + plane * 2));
594 CUSTOM_REG_LONG(REG_BPL1PTH + plane * 2) += 2;
595 }
596
597
598 /*************************************
599 *
600 * Hold and modify pixel computations
601 *
602 *************************************/
603
update_ham(int newpix)604 int amiga_state::update_ham(int newpix)
605 {
606 switch (newpix >> 4)
607 {
608 case 0:
609 m_ham_color = CUSTOM_REG(REG_COLOR00 + (newpix & 0xf));
610 break;
611
612 case 1:
613 m_ham_color = (m_ham_color & 0xff0) | ((newpix & 0xf) << 0);
614 break;
615
616 case 2:
617 m_ham_color = (m_ham_color & 0x0ff) | ((newpix & 0xf) << 8);
618 break;
619
620 case 3:
621 m_ham_color = (m_ham_color & 0xf0f) | ((newpix & 0xf) << 4);
622 break;
623 }
624 return m_ham_color;
625 }
626
627
628 //**************************************************************************
629 // DISPLAY WINDOW
630 //**************************************************************************
631
update_display_window()632 void amiga_state::update_display_window()
633 {
634 int vstart = CUSTOM_REG(REG_DIWSTRT) >> 8;
635 int vstop = CUSTOM_REG(REG_DIWSTOP) >> 8;
636 int hstart = CUSTOM_REG(REG_DIWSTRT) & 0xff;
637 int hstop = CUSTOM_REG(REG_DIWSTOP) & 0xff;
638
639 if (m_diwhigh_valid)
640 {
641 vstart |= (CUSTOM_REG(REG_DIWHIGH) & 7) << 8;
642 vstop |= ((CUSTOM_REG(REG_DIWHIGH) >> 8) & 7) << 8;
643 hstart |= ((CUSTOM_REG(REG_DIWHIGH) >> 5) & 1) << 8;
644 hstop |= ((CUSTOM_REG(REG_DIWHIGH) >> 13) & 1) << 8;
645 }
646 else
647 {
648 vstop |= ((~CUSTOM_REG(REG_DIWSTOP) >> 7) & 0x100);
649 hstop |= 0x100;
650 }
651
652 if (hstop < hstart)
653 {
654 hstart = 0x00;
655 hstop = 0x1ff;
656 }
657
658 m_diw.set(hstart, hstop, vstart, vstop);
659 }
660
661
662 /*************************************
663 *
664 * Single scanline rasterizer
665 *
666 *************************************/
667
render_scanline(bitmap_rgb32 & bitmap,int scanline)668 void amiga_state::render_scanline(bitmap_rgb32 &bitmap, int scanline)
669 {
670 uint16_t save_color0 = CUSTOM_REG(REG_COLOR00);
671 int ddf_start_pixel = 0, ddf_stop_pixel = 0;
672 int hires = 0, dualpf = 0, ham = 0;
673 int pf1pri = 0, pf2pri = 0;
674 int planes = 0;
675
676 uint32_t *dst = nullptr;
677 int ebitoffs = 0, obitoffs = 0;
678 int ecolmask = 0, ocolmask = 0;
679 int edelay = 0, odelay = 0;
680 int next_copper_x;
681 int pl;
682 const int defbitoffs = 15;
683
684 int save_scanline = scanline;
685
686 // we need to do a bit more work on the first scanline
687 if (scanline == 0)
688 {
689 m_previous_lof = CUSTOM_REG(REG_VPOSR) & VPOSR_LOF;
690
691 // toggle lof if enabled
692 if (CUSTOM_REG(REG_BPLCON0) & BPLCON0_LACE)
693 CUSTOM_REG(REG_VPOSR) ^= VPOSR_LOF;
694
695 // reset copper and ham color
696 copper_setpc(CUSTOM_REG_LONG(REG_COP1LCH));
697 m_ham_color = CUSTOM_REG(REG_COLOR00);
698 }
699
700 // in visible area?
701 if (bitmap.valid())
702 {
703 bool lof = CUSTOM_REG(REG_VPOSR) & VPOSR_LOF;
704
705 if ((scanline & 1) ^ lof)
706 {
707 // lof matches? then render this scanline
708 dst = &bitmap.pix(scanline);
709 }
710 else
711 {
712 // lof doesn't match, we don't render this scanline
713 // if we didn't switch lof we have a full non-interlace screen,
714 // so we fill the black gaps with the contents of the previous scanline
715 // otherwise just render the contents of the previous frame's scanline
716 int shift = (m_previous_lof == lof) ? 1 : 0;
717
718 std::copy_n(&m_flickerfixer.pix(scanline - shift), amiga_state::SCREEN_WIDTH, &bitmap.pix(scanline));
719 return;
720 }
721 }
722
723 scanline /= 2;
724
725 m_last_scanline = scanline;
726
727 /* update sprite data fetching */
728 update_sprite_dma(scanline);
729
730 /* all sprites off at the start of the line */
731 memset(m_sprite_remain, 0, sizeof(m_sprite_remain));
732
733 /* temporary set color 0 to the genlock color */
734 if (m_genlock_color != 0xffff)
735 CUSTOM_REG(REG_COLOR00) = m_genlock_color;
736
737 /* loop over the line */
738 next_copper_x = 0;
739 for (int x = 0; x < amiga_state::SCREEN_WIDTH / 2; x++)
740 {
741 int sprpix;
742
743 /* time to execute the copper? */
744 if (x == next_copper_x)
745 {
746 /* execute the next batch, restoring and re-saving color 0 around it */
747 CUSTOM_REG(REG_COLOR00) = save_color0;
748 next_copper_x = copper_execute_next(x);
749 save_color0 = CUSTOM_REG(REG_COLOR00);
750 if (m_genlock_color != 0xffff)
751 CUSTOM_REG(REG_COLOR00) = m_genlock_color;
752
753 /* compute update-related register values */
754 planes = (CUSTOM_REG(REG_BPLCON0) & (BPLCON0_BPU0 | BPLCON0_BPU1 | BPLCON0_BPU2)) >> 12;
755 hires = CUSTOM_REG(REG_BPLCON0) & BPLCON0_HIRES;
756 ham = CUSTOM_REG(REG_BPLCON0) & BPLCON0_HOMOD;
757 dualpf = CUSTOM_REG(REG_BPLCON0) & BPLCON0_DBLPF;
758
759 /* compute the pixel fetch parameters */
760 ddf_start_pixel = (CUSTOM_REG(REG_DDFSTRT) & (hires ? 0xfc : 0xf8)) * 2;
761 ddf_start_pixel += hires ? 9 : 17;
762 ddf_stop_pixel = (CUSTOM_REG(REG_DDFSTOP) & (hires ? 0xfc : 0xf8)) * 2;
763 ddf_stop_pixel += hires ? (9 + defbitoffs) : (17 + defbitoffs);
764
765 if ( ( CUSTOM_REG(REG_DDFSTRT) ^ CUSTOM_REG(REG_DDFSTOP) ) & 0x04 )
766 ddf_stop_pixel += 8;
767
768 // display window
769 update_display_window();
770
771 /* extract playfield priorities */
772 pf1pri = CUSTOM_REG(REG_BPLCON2) & 7;
773 pf2pri = (CUSTOM_REG(REG_BPLCON2) >> 3) & 7;
774
775 /* extract collision masks */
776 ocolmask = (CUSTOM_REG(REG_CLXCON) >> 6) & 0x15;
777 ecolmask = (CUSTOM_REG(REG_CLXCON) >> 6) & 0x2a;
778 }
779
780 /* clear the target pixels to the background color as a starting point */
781 if (dst != nullptr)
782 dst[x*2+0] =
783 dst[x*2+1] = m_palette->pen(CUSTOM_REG(REG_COLOR00));
784
785 /* if we hit the first fetch pixel, reset the counters and latch the delays */
786 if (x == ddf_start_pixel)
787 {
788 odelay = CUSTOM_REG(REG_BPLCON1) & 0xf;
789 edelay = ( CUSTOM_REG(REG_BPLCON1) >> 4 ) & 0x0f;
790
791 if ( hires )
792 {
793 obitoffs = defbitoffs + ( odelay << 1 );
794 ebitoffs = defbitoffs + ( edelay << 1 );
795 }
796 else
797 {
798 if ( CUSTOM_REG(REG_DDFSTRT) & 0x04 )
799 {
800 odelay = ( odelay + 8 ) & 0x0f;
801 edelay = ( edelay + 8 ) & 0x0f;
802 }
803
804 obitoffs = defbitoffs + odelay;
805 ebitoffs = defbitoffs + edelay;
806 }
807
808 for (pl = 0; pl < 6; pl++)
809 CUSTOM_REG(REG_BPL1DAT + pl) = 0;
810 }
811
812 /* need to run the sprite engine every pixel to ensure display */
813 sprpix = get_sprite_pixel(x);
814
815 /* to render, we must have bitplane DMA enabled, at least 1 plane, and be within the */
816 /* vertical display window */
817 if ((CUSTOM_REG(REG_DMACON) & (DMACON_BPLEN | DMACON_DMAEN)) == (DMACON_BPLEN | DMACON_DMAEN) &&
818 planes > 0 && scanline >= m_diw.top() && scanline < m_diw.bottom())
819 {
820 int pfpix0 = 0, pfpix1 = 0, collide;
821
822 /* fetch the odd bits if we are within the fetching region */
823 if (x >= ddf_start_pixel && x <= ddf_stop_pixel + odelay)
824 {
825 /* if we need to fetch more data, do it now */
826 if (obitoffs == defbitoffs)
827 {
828 for (pl = 0; pl < planes; pl += 2)
829 {
830 fetch_bitplane_data(pl);
831 }
832 }
833
834 /* now assemble the bits */
835 pfpix0 |= assemble_odd_bitplanes(planes, obitoffs);
836 obitoffs--;
837
838 /* for high res, assemble a second set of bits */
839 if (hires)
840 {
841 /* reset bit offsets and fetch more data if needed */
842 if (obitoffs < 0)
843 {
844 obitoffs = defbitoffs;
845
846 for (pl = 0; pl < planes; pl += 2)
847 {
848 fetch_bitplane_data(pl);
849 }
850 }
851
852 pfpix1 |= assemble_odd_bitplanes(planes, obitoffs);
853 obitoffs--;
854 }
855 else
856 pfpix1 |= pfpix0 & 0x15;
857
858 /* reset bit offsets if needed */
859 if (obitoffs < 0)
860 obitoffs = defbitoffs;
861 }
862
863 /* fetch the even bits if we are within the fetching region */
864 if (x >= ddf_start_pixel && x <= ddf_stop_pixel + edelay)
865 {
866 /* if we need to fetch more data, do it now */
867 if (ebitoffs == defbitoffs)
868 {
869 for (pl = 1; pl < planes; pl += 2)
870 {
871 fetch_bitplane_data(pl);
872 }
873 }
874
875 /* now assemble the bits */
876 pfpix0 |= assemble_even_bitplanes(planes, ebitoffs);
877 ebitoffs--;
878
879 /* for high res, assemble a second set of bits */
880 if (hires)
881 {
882 /* reset bit offsets and fetch more data if needed */
883 if (ebitoffs < 0)
884 {
885 ebitoffs = defbitoffs;
886
887 for (pl = 1; pl < planes; pl += 2)
888 {
889 fetch_bitplane_data(pl);
890 }
891 }
892
893 pfpix1 |= assemble_even_bitplanes(planes, ebitoffs);
894 ebitoffs--;
895 }
896 else
897 pfpix1 |= pfpix0 & 0x2a;
898
899 /* reset bit offsets if needed */
900 if (ebitoffs < 0)
901 ebitoffs = defbitoffs;
902 }
903
904 /* compute playfield/sprite collisions for first pixel */
905 collide = pfpix0 ^ CUSTOM_REG(REG_CLXCON);
906 if ((collide & ocolmask) == 0)
907 CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 5) & 0x01e;
908 if ((collide & ecolmask) == 0)
909 CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 1) & 0x1e0;
910 if ((collide & (ecolmask | ocolmask)) == 0)
911 CUSTOM_REG(REG_CLXDAT) |= 0x001;
912
913 /* compute playfield/sprite collisions for second pixel */
914 collide = pfpix1 ^ CUSTOM_REG(REG_CLXCON);
915 if ((collide & ocolmask) == 0)
916 CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 5) & 0x01e;
917 if ((collide & ecolmask) == 0)
918 CUSTOM_REG(REG_CLXDAT) |= (sprpix >> 1) & 0x1e0;
919 if ((collide & (ecolmask | ocolmask)) == 0)
920 CUSTOM_REG(REG_CLXDAT) |= 0x001;
921
922 /* if we are within the display region, render */
923 if (dst != nullptr && x >= m_diw.left() && x < m_diw.right())
924 {
925 int pix, pri;
926
927 /* hold-and-modify mode -- assume low-res (hi-res not supported by the hardware) */
928 if (ham)
929 {
930 /* update the HAM color */
931 pfpix0 = update_ham(pfpix0);
932
933 pix = sprpix & 0x1f;
934 pri = (sprpix >> 10);
935
936 /* sprite has priority */
937 if (sprpix && pf1pri > pri)
938 {
939 dst[x*2+0] =
940 dst[x*2+1] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + pix));
941 }
942
943 /* playfield has priority */
944 else
945 {
946 dst[x*2+0] =
947 dst[x*2+1] = m_palette->pen(pfpix0);
948 }
949 }
950
951 /* dual playfield mode */
952 else if (dualpf)
953 {
954 /* mask out the sprite if it doesn't have priority */
955 pix = sprpix & 0x1f;
956 pri = (sprpix >> 10);
957 if (pix)
958 {
959 if ((pfpix0 & 0x15) && pf1pri <= pri)
960 pix = 0;
961 if ((pfpix0 & 0x2a) && pf2pri <= pri)
962 pix = 0;
963 }
964
965 /* write out the left pixel */
966 if (pix)
967 dst[x*2+0] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + pix));
968 else
969 dst[x*2+0] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + m_separate_bitplanes[(CUSTOM_REG(REG_BPLCON2) >> 6) & 1][pfpix0]));
970
971 /* mask out the sprite if it doesn't have priority */
972 pix = sprpix & 0x1f;
973 if (pix)
974 {
975 if ((pfpix1 & 0x15) && pf1pri <= pri)
976 pix = 0;
977 if ((pfpix1 & 0x2a) && pf2pri <= pri)
978 pix = 0;
979 }
980
981 /* write out the right pixel */
982 if (pix)
983 dst[x*2+1] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + pix));
984 else
985 dst[x*2+1] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + m_separate_bitplanes[(CUSTOM_REG(REG_BPLCON2) >> 6) & 1][pfpix1]));
986 }
987
988 /* single playfield mode */
989 else
990 {
991 pix = sprpix & 0x1f;
992 pri = (sprpix >> 10);
993
994 /* sprite has priority */
995 if (sprpix && pf1pri > pri)
996 {
997 dst[x*2+0] =
998 dst[x*2+1] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + pix));
999 }
1000
1001 /* playfield has priority */
1002 else
1003 {
1004 dst[x*2+0] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + pfpix0));
1005 dst[x*2+1] = m_palette->pen(CUSTOM_REG(REG_COLOR00 + pfpix1));
1006 }
1007 }
1008 }
1009 }
1010 }
1011
1012 // end of the line: time to add the modulos
1013 if (scanline >= m_diw.top() && scanline < m_diw.bottom())
1014 {
1015 // update odd planes
1016 for (pl = 0; pl < planes; pl += 2)
1017 CUSTOM_REG_LONG(REG_BPL1PTH + pl * 2) += CUSTOM_REG_SIGNED(REG_BPL1MOD);
1018
1019 // update even planes
1020 for (pl = 1; pl < planes; pl += 2)
1021 CUSTOM_REG_LONG(REG_BPL1PTH + pl * 2) += CUSTOM_REG_SIGNED(REG_BPL2MOD);
1022 }
1023
1024 // restore color00
1025 CUSTOM_REG(REG_COLOR00) = save_color0;
1026
1027 // save
1028 if (dst != nullptr)
1029 std::copy_n(dst, amiga_state::SCREEN_WIDTH, &m_flickerfixer.pix(save_scanline));
1030
1031 #if GUESS_COPPER_OFFSET
1032 if (m_screen->frame_number() % 64 == 0 && scanline == 0)
1033 {
1034 if (machine().input().code_pressed(KEYCODE_Q))
1035 popmessage("%d", m_wait_offset -= 1);
1036 if (machine().input().code_pressed(KEYCODE_W))
1037 popmessage("%d", m_wait_offset += 1);
1038 }
1039 #endif
1040 }
1041
1042
1043
1044 /*************************************
1045 *
1046 * Update
1047 *
1048 *************************************/
1049
screen_update_amiga(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1050 uint32_t amiga_state::screen_update_amiga(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1051 {
1052 // sometimes the core tells us to render a bunch of lines to keep up (resolution change, for example)
1053 // this causes trouble for us since it can happen at any time
1054 if (cliprect.top() != cliprect.bottom())
1055 return 0;
1056
1057 // render each scanline in the visible region
1058 for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
1059 render_scanline(bitmap, y);
1060
1061 return 0;
1062 }
1063
update_screenmode()1064 void amiga_state::update_screenmode()
1065 {
1066 bool pal;
1067
1068 // first let's see if we're PAL or NTSC
1069 if (m_agnus_id >= AGNUS_HR_PAL)
1070 // we support dynamic switching between PAL and NTSC, determine mode from register
1071 pal = CUSTOM_REG(REG_BEAMCON0) & 0x20;
1072 else
1073 // old agnus, agnus id determines PAL or NTSC
1074 pal = !(m_agnus_id & 0x10);
1075
1076 // basic height & vblank length
1077 int height = pal ? SCREEN_HEIGHT_PAL : SCREEN_HEIGHT_NTSC;
1078 int vblank = pal ? VBLANK_PAL : VBLANK_NTSC;
1079
1080 // frame period
1081 attoseconds_t period = HZ_TO_ATTOSECONDS(m_screen->clock()) * SCREEN_WIDTH * height;
1082
1083 // adjust visible area
1084 rectangle visarea = m_screen->visible_area();
1085 visarea.sety(vblank, height - 1);
1086
1087 // finally set our new mode
1088 m_screen->configure(SCREEN_WIDTH, height, visarea, period);
1089 }
1090
1091
1092 //**************************************************************************
1093 // MACHINE DRIVER FRAGMENTS
1094 //**************************************************************************
1095
pal_video(machine_config & config)1096 void amiga_state::pal_video(machine_config &config)
1097 {
1098 SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
1099 m_screen->set_raw
1100 (
1101 (amiga_state::CLK_28M_PAL / 4) * 2 * 2,
1102 amiga_state::SCREEN_WIDTH, amiga_state::HBLANK, amiga_state::SCREEN_WIDTH,
1103 amiga_state::SCREEN_HEIGHT_PAL, amiga_state::VBLANK_PAL, amiga_state::SCREEN_HEIGHT_PAL
1104 );
1105 m_screen->set_screen_update(FUNC(amiga_state::screen_update_amiga));
1106 }
1107
ntsc_video(machine_config & config)1108 void amiga_state::ntsc_video(machine_config &config)
1109 {
1110 SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
1111 m_screen->set_raw
1112 (
1113 (amiga_state::CLK_28M_NTSC / 4) * 2 * 2,
1114 amiga_state::SCREEN_WIDTH, amiga_state::HBLANK, amiga_state::SCREEN_WIDTH,
1115 amiga_state::SCREEN_HEIGHT_NTSC, amiga_state::VBLANK_NTSC, amiga_state::SCREEN_HEIGHT_NTSC
1116 );
1117 m_screen->set_screen_update(FUNC(amiga_state::screen_update_amiga));
1118 }
1119