1 /*
2 * vicii.c - A cycle-exact event-driven MOS6569 (VIC-II) emulation.
3 *
4 * Written by
5 * Ettore Perazzoli <ettore@comm2000.it>
6 * Andreas Boose <viceteam@t-online.de>
7 *
8 * DTV sections written by
9 * Hannu Nuotio <hannu.nuotio@tut.fi>
10 * Daniel Kahlin <daniel@kahlin.net>
11 *
12 * This file is part of VICE, the Versatile Commodore Emulator.
13 * See README for copyright notice.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 * 02111-1307 USA.
29 *
30 */
31
32 /* TODO: - speed optimizations;
33 - faster sprites and registers. */
34
35 /*
36 Current (most important) known limitations:
37
38 - sprite colors (and other attributes) cannot change in the middle of the
39 raster line;
40
41 Probably something else which I have not figured out yet...
42
43 */
44
45 #include "vice.h"
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include "videoarch.h"
52
53 #include "alarm.h"
54 #include "c64.h"
55 #include "cartridge.h"
56 #include "c64cart.h"
57 #include "c64cartmem.h"
58 #include "c64dtvblitter.h"
59 #include "c64dtvdma.h"
60 #include "clkguard.h"
61 #include "dma.h"
62 #include "lib.h"
63 #include "log.h"
64 #include "machine.h"
65 #include "maincpu.h"
66 #include "mem.h"
67 #include "monitor.h"
68 #include "raster-changes.h"
69 #include "raster-line.h"
70 #include "raster-modes.h"
71 #include "raster-sprite-status.h"
72 #include "raster-sprite.h"
73 #include "resources.h"
74 #include "screenshot.h"
75 #include "types.h"
76 #include "vicii-cmdline-options.h"
77 #include "vicii-color.h"
78 #include "vicii-draw.h"
79 #include "vicii-fetch.h"
80 #include "vicii-irq.h"
81 #include "vicii-mem.h"
82 #include "vicii-sprites.h"
83 #include "vicii-resources.h"
84 #include "vicii-timing.h"
85 #include "vicii.h"
86 #include "viciitypes.h"
87 #include "vsync.h"
88 #include "video.h"
89 #include "viewport.h"
90
91
vicii_set_phi1_addr_options(uint16_t mask,uint16_t offset)92 void vicii_set_phi1_addr_options(uint16_t mask, uint16_t offset)
93 {
94 vicii.vaddr_mask_phi1 = mask;
95 vicii.vaddr_offset_phi1 = offset;
96
97 VICII_DEBUG_REGISTER(("Set phi1 video addr mask=%04x, offset=%04x", mask, offset));
98 vicii_update_memory_ptrs_external();
99 }
100
vicii_set_phi2_addr_options(uint16_t mask,uint16_t offset)101 void vicii_set_phi2_addr_options(uint16_t mask, uint16_t offset)
102 {
103 vicii.vaddr_mask_phi2 = mask;
104 vicii.vaddr_offset_phi2 = offset;
105
106 VICII_DEBUG_REGISTER(("Set phi2 video addr mask=%04x, offset=%04x", mask, offset));
107 vicii_update_memory_ptrs_external();
108 }
109
vicii_set_phi1_chargen_addr_options(uint16_t mask,uint16_t value)110 void vicii_set_phi1_chargen_addr_options(uint16_t mask, uint16_t value)
111 {
112 vicii.vaddr_chargen_mask_phi1 = mask;
113 vicii.vaddr_chargen_value_phi1 = value;
114
115 VICII_DEBUG_REGISTER(("Set phi1 chargen addr mask=%04x, value=%04x", mask, value));
116 vicii_update_memory_ptrs_external();
117 }
118
vicii_set_phi2_chargen_addr_options(uint16_t mask,uint16_t value)119 void vicii_set_phi2_chargen_addr_options(uint16_t mask, uint16_t value)
120 {
121 vicii.vaddr_chargen_mask_phi2 = mask;
122 vicii.vaddr_chargen_value_phi2 = value;
123
124 VICII_DEBUG_REGISTER(("Set phi2 chargen addr mask=%04x, value=%04x", mask, value));
125 vicii_update_memory_ptrs_external();
126 }
127
vicii_set_chargen_addr_options(uint16_t mask,uint16_t value)128 void vicii_set_chargen_addr_options(uint16_t mask, uint16_t value)
129 {
130 vicii.vaddr_chargen_mask_phi1 = mask;
131 vicii.vaddr_chargen_value_phi1 = value;
132 vicii.vaddr_chargen_mask_phi2 = mask;
133 vicii.vaddr_chargen_value_phi2 = value;
134
135 VICII_DEBUG_REGISTER(("Set chargen addr mask=%04x, value=%04x", mask, value));
136 vicii_update_memory_ptrs_external();
137 }
138
139 /* ---------------------------------------------------------------------*/
140
141 vicii_t vicii;
142
143 static void vicii_set_geometry(void);
144
clk_overflow_callback(CLOCK sub,void * unused_data)145 static void clk_overflow_callback(CLOCK sub, void *unused_data)
146 {
147 vicii.raster_irq_clk -= sub;
148 vicii.last_emulate_line_clk -= sub;
149 vicii.fetch_clk -= sub;
150 vicii.draw_clk -= sub;
151 vicii.sprite_fetch_clk -= sub;
152 }
153
vicii_change_timing(machine_timing_t * machine_timing,int border_mode)154 void vicii_change_timing(machine_timing_t *machine_timing, int border_mode)
155 {
156 vicii_timing_set(machine_timing, border_mode);
157
158 if (vicii.initialized) {
159 vicii_set_geometry();
160 raster_mode_change();
161 }
162 }
163
164 static CLOCK old_maincpu_clk = 0;
165
vicii_delay_oldclk(CLOCK num)166 void vicii_delay_oldclk(CLOCK num)
167 {
168 old_maincpu_clk += num;
169 }
170
vicii_delay_clk(void)171 inline void vicii_delay_clk(void)
172 {
173 #if 0
174 CLOCK diff;
175
176 /*log_debug("MCLK %d OMCLK %d", maincpu_clk, old_maincpu_clk);*/
177
178 if (vicii.fastmode == 0) {
179 diff = maincpu_clk - old_maincpu_clk;
180
181 if (!vicii.badline_disable) {
182 dma_maincpu_steal_cycles(maincpu_clk, diff, 0);
183 }
184 }
185
186 old_maincpu_clk = maincpu_clk;
187
188 return;
189 #endif
190 }
191
vicii_handle_pending_alarms(int num_write_cycles)192 inline void vicii_handle_pending_alarms(int num_write_cycles)
193 {
194 if (vicii.viciie != 0) {
195 vicii_delay_clk();
196 }
197
198 if (num_write_cycles != 0) {
199 int f;
200
201 /* Cycles can be stolen only during the read accesses, so we serve
202 only the events that happened during them. The last read access
203 happened at `clk - maincpu_write_cycles()' as all the opcodes
204 except BRK and JSR do all the write accesses at the very end. BRK
205 cannot take us here and we would not be able to handle JSR
206 correctly anyway, so we don't care about them... */
207
208 /* Go back to the time when the read accesses happened and serve VIC
209 events. */
210 maincpu_clk -= num_write_cycles;
211
212 do {
213 f = 0;
214 if (maincpu_clk > vicii.fetch_clk) {
215 vicii_fetch_alarm_handler(0, NULL);
216 f = 1;
217 if (vicii.viciie != 0) {
218 vicii_delay_clk();
219 }
220 }
221 if (maincpu_clk >= vicii.draw_clk) {
222 vicii_raster_draw_alarm_handler((CLOCK)(maincpu_clk - vicii.draw_clk), NULL);
223 f = 1;
224 if (vicii.viciie != 0) {
225 vicii_delay_clk();
226 }
227 }
228 }
229 while (f);
230
231 /* Go forward to the time when the last write access happens (that's
232 the one we care about, as the only instructions that do two write
233 accesses - except BRK and JSR - are the RMW ones, which store the
234 old value in the first write access, and then store the new one in
235 the second write access). */
236 maincpu_clk += num_write_cycles;
237 } else {
238 int f;
239
240 do {
241 f = 0;
242 if (maincpu_clk >= vicii.fetch_clk) {
243 vicii_fetch_alarm_handler(0, NULL);
244 f = 1;
245 if (vicii.viciie != 0) {
246 vicii_delay_clk();
247 }
248 }
249 if (maincpu_clk >= vicii.draw_clk) {
250 vicii_raster_draw_alarm_handler(0, NULL);
251 f = 1;
252 if (vicii.viciie != 0) {
253 vicii_delay_clk();
254 }
255 }
256 }
257 while (f);
258 }
259 }
260
vicii_handle_pending_alarms_external(int num_write_cycles)261 void vicii_handle_pending_alarms_external(int num_write_cycles)
262 {
263 if (vicii.initialized) {
264 vicii_handle_pending_alarms(num_write_cycles);
265 }
266 }
267
vicii_handle_pending_alarms_external_write(void)268 void vicii_handle_pending_alarms_external_write(void)
269 {
270 /* WARNING: assumes `maincpu_rmw_flag' is 0 or 1. */
271 if (vicii.initialized) {
272 vicii_handle_pending_alarms(maincpu_rmw_flag + 1);
273 }
274 }
275
276 /* return pixel aspect ratio for current video mode
277 * based on http://codebase64.com/doku.php?id=base:pixel_aspect_ratio
278 */
vicii_get_pixel_aspect(void)279 static float vicii_get_pixel_aspect(void)
280 {
281 int video;
282 resources_get_int("MachineVideoStandard", &video);
283 switch (video) {
284 case MACHINE_SYNC_PAL:
285 return 0.93650794f;
286 case MACHINE_SYNC_PALN:
287 return 0.90769231f;
288 case MACHINE_SYNC_NTSC:
289 return 0.75000000f;
290 case MACHINE_SYNC_NTSCOLD:
291 return 0.76171875f;
292 default:
293 return 1.0f;
294 }
295 }
296
297 /* return type of monitor used for current video mode */
vicii_get_crt_type(void)298 static int vicii_get_crt_type(void)
299 {
300 int video;
301 resources_get_int("MachineVideoStandard", &video);
302 switch (video) {
303 case MACHINE_SYNC_PAL:
304 case MACHINE_SYNC_PALN:
305 return 1; /* PAL */
306 default:
307 return 0; /* NTSC */
308 }
309 }
310
vicii_set_geometry(void)311 static void vicii_set_geometry(void)
312 {
313 unsigned int width, height;
314
315 width = vicii.screen_leftborderwidth + VICII_SCREEN_XPIX + vicii.screen_rightborderwidth;
316 height = vicii.last_displayed_line - vicii.first_displayed_line + 1;
317
318 raster_set_geometry(&vicii.raster,
319 width, height, /* canvas dimensions */
320 width, vicii.screen_height, /* screen dimensions */
321 VICII_SCREEN_XPIX, VICII_SCREEN_YPIX, /* gfx dimensions */
322 VICII_SCREEN_TEXTCOLS, VICII_SCREEN_TEXTLINES, /* text dimensions */
323 vicii.screen_leftborderwidth, vicii.row_25_start_line, /* gfx position */
324 vicii.viciidtv ? 1 : 0, /* gfx area doesn't move except on DTV*/
325 vicii.first_displayed_line,
326 vicii.last_displayed_line,
327 -VICII_RASTER_X(0), /* extra offscreen border left */
328 vicii.sprite_wrap_x - VICII_SCREEN_XPIX -
329 vicii.screen_leftborderwidth - vicii.screen_rightborderwidth + VICII_RASTER_X(0)) /* extra offscreen border right */;
330
331 vicii.raster.geometry->pixel_aspect_ratio = vicii_get_pixel_aspect();
332 vicii.raster.viewport->crt_type = vicii_get_crt_type();
333 }
334
init_raster(void)335 static int init_raster(void)
336 {
337 raster_t *raster;
338
339 raster = &vicii.raster;
340
341 raster_sprite_status_new(raster, VICII_NUM_SPRITES, vicii_sprite_offset());
342 raster_line_changes_sprite_init(raster);
343
344 /* FIXME: VICII_NUM_VMODES is only valid for DTV.
345 A smaller number could be used for !DTV, but
346 VICII_IDLE_MODE needs to be < VICII_NUM_VMODES. */
347 if (raster_init(raster, VICII_NUM_VMODES) < 0) {
348 return -1;
349 }
350 raster_modes_set_idle_mode(raster->modes, VICII_IDLE_MODE);
351 resources_touch("VICIIVideoCache");
352
353 vicii_set_geometry();
354
355 if (vicii_color_update_palette(raster->canvas) < 0) {
356 log_error(vicii.log, "Cannot load palette.");
357 return -1;
358 }
359
360 raster_set_title(raster, machine_name);
361
362 if (raster_realize(raster) < 0) {
363 return -1;
364 }
365 raster->display_ystart = vicii.row_25_start_line;
366 raster->display_ystop = vicii.row_25_stop_line;
367 raster->display_xstart = VICII_40COL_START_PIXEL;
368 raster->display_xstop = VICII_40COL_STOP_PIXEL;
369
370 if (vicii.viciidtv) {
371 raster->can_disable_border = 1;
372 }
373 return 0;
374 }
375
376 /* Initialize the VIC-II emulation. */
vicii_init(unsigned int flag)377 raster_t *vicii_init(unsigned int flag)
378 {
379 vicii.fastmode = 0;
380 vicii.half_cycles = 0;
381
382 switch (flag) {
383 case VICII_EXTENDED:
384 vicii.viciie = 1;
385 vicii.viciidtv = 0;
386 vicii.log = log_open("VIC-IIe");
387 break;
388 case VICII_DTV:
389 vicii.viciie = 0;
390 vicii.viciidtv = 1;
391 vicii.log = log_open("VIC-II DTV");
392 break;
393 default:
394 case VICII_STANDARD:
395 vicii.viciie = 0;
396 vicii.viciidtv = 0;
397 vicii.log = log_open("VIC-II");
398 break;
399 }
400
401 vicii_irq_init();
402
403 vicii_fetch_init();
404
405 vicii.raster_draw_alarm = alarm_new(maincpu_alarm_context,
406 "VicIIRasterDraw",
407 vicii_raster_draw_alarm_handler, NULL);
408 if (init_raster() < 0) {
409 return NULL;
410 }
411
412 vicii_powerup();
413
414 vicii.video_mode = -1;
415 vicii_update_video_mode(0);
416 vicii_update_memory_ptrs(0);
417
418 vicii_draw_init();
419 vicii_sprites_init();
420
421 vicii.num_idle_3fff = 0;
422 vicii.num_idle_3fff_old = 0;
423 vicii.idle_3fff = lib_malloc(sizeof(idle_3fff_t) * 64);
424 vicii.idle_3fff_old = lib_malloc(sizeof(idle_3fff_t) * 64);
425
426 vicii.buf_offset = 0;
427
428 vicii.initialized = 1;
429
430 clk_guard_add_callback(maincpu_clk_guard, clk_overflow_callback, NULL);
431
432 return &vicii.raster;
433 }
434
vicii_get_canvas(void)435 struct video_canvas_s *vicii_get_canvas(void)
436 {
437 return vicii.raster.canvas;
438 }
439
440 /* Reset the VIC-II chip. */
vicii_reset(void)441 void vicii_reset(void)
442 {
443 int i;
444
445 raster_reset(&vicii.raster);
446
447 vicii.last_emulate_line_clk = 0;
448
449 vicii.draw_clk = vicii.draw_cycle;
450 alarm_set(vicii.raster_draw_alarm, vicii.draw_clk);
451
452 vicii.fetch_clk = VICII_FETCH_CYCLE;
453 alarm_set(vicii.raster_fetch_alarm, vicii.fetch_clk);
454 vicii.fetch_idx = VICII_FETCH_MATRIX;
455 vicii.sprite_fetch_idx = 0;
456 vicii.sprite_fetch_msk = 0;
457 vicii.sprite_fetch_clk = CLOCK_MAX;
458
459 /* FIXME: I am not sure this is exact emulation. */
460 vicii.raster_irq_line = 0;
461 vicii.raster_irq_clk = 0;
462 vicii.regs[0x11] = 0;
463 vicii.regs[0x12] = 0;
464
465 /* Setup the raster IRQ alarm. The value is `1' instead of `0' because we
466 are at the first line, which has a +1 clock cycle delay in IRQs. */
467 alarm_set(vicii.raster_irq_alarm, 1);
468
469 vicii.force_display_state = 0;
470
471 vicii.light_pen.state = 0;
472 vicii.light_pen.triggered = 0;
473 vicii.light_pen.x = vicii.light_pen.y = vicii.light_pen.x_extra_bits = 0;
474
475 /* Remove all the IRQ sources. */
476 vicii.regs[0x1a] = 0;
477
478 vicii.raster.display_ystart = vicii.row_25_start_line;
479 vicii.raster.display_ystop = vicii.row_25_stop_line;
480
481 vicii.store_clk = CLOCK_MAX;
482
483 vicii.counta = 0;
484 vicii.counta_mod = 0;
485 vicii.counta_step = 0;
486 vicii.countb = 0;
487 vicii.countb_mod = 0;
488 vicii.countb_step = 0;
489 for (i = 0; i < 256; i++) {
490 vicii.dtvpalette[i] = i;
491 }
492
493 vicii.dtvpalette[0] = 0;
494 vicii.dtvpalette[1] = 0x0f;
495 vicii.dtvpalette[2] = 0x36;
496 vicii.dtvpalette[3] = 0xbe;
497 vicii.dtvpalette[4] = 0x58;
498 vicii.dtvpalette[5] = 0xdb;
499 vicii.dtvpalette[6] = 0x86;
500 vicii.dtvpalette[7] = 0xff;
501 vicii.dtvpalette[8] = 0x29;
502 vicii.dtvpalette[9] = 0x26;
503 vicii.dtvpalette[10] = 0x3b;
504 vicii.dtvpalette[11] = 0x05;
505 vicii.dtvpalette[12] = 0x07;
506 vicii.dtvpalette[13] = 0xdf;
507 vicii.dtvpalette[14] = 0x9a;
508 vicii.dtvpalette[15] = 0x0a;
509
510 /* clear the high nibble from colors so that standard colors can be written without
511 having extended_enable=1 */
512 vicii.regs[0x20] &= 0xf;
513 vicii.regs[0x21] &= 0xf;
514 vicii.regs[0x22] &= 0xf;
515 vicii.regs[0x23] &= 0xf;
516 vicii.regs[0x24] &= 0xf;
517
518 vicii.regs[0x3c] = 0;
519
520 vicii.regs[0x36] = 0x76;
521 vicii.regs[0x37] = 0;
522
523 /* clear count[ab] & other regs,
524 fixes problem with DTVBIOS, gfxmodes & soft reset */
525 vicii.regs[0x38] = 0;
526 vicii.regs[0x39] = 0;
527 vicii.regs[0x3a] = 0;
528 vicii.regs[0x3b] = 0;
529 vicii.regs[0x3d] = 0;
530 vicii.regs[0x44] = 64;
531 vicii.regs[0x45] = 0;
532 vicii.regs[0x46] = 0;
533 vicii.regs[0x47] = 0;
534 vicii.regs[0x48] = 0;
535 vicii.regs[0x49] = 0;
536 vicii.regs[0x4a] = 0;
537 vicii.regs[0x4b] = 0;
538 vicii.regs[0x4c] = 0;
539 vicii.regs[0x4d] = 0;
540
541 vicii.extended_enable = 0;
542 vicii.badline_disable = 0;
543 vicii.colorfetch_disable = 0;
544 vicii.border_off = 0;
545 vicii.overscan = 0;
546 vicii.color_ram_ptr = &mem_ram[0x01d800];
547
548 vicii.raster_irq_offset = 0;
549 vicii.raster_irq_prevent = 0;
550
551 /* Disable DTV features on non-DTV VIC-II */
552 if (!vicii.viciidtv) {
553 vicii.extended_lockout = 1;
554 } else {
555 vicii.extended_lockout = 0;
556 }
557 }
558
vicii_reset_registers(void)559 void vicii_reset_registers(void)
560 {
561 uint16_t i;
562
563 if (!vicii.initialized) {
564 return;
565 }
566
567 if (!vicii.viciidtv) {
568 for (i = 0; i <= 0x3f; i++) {
569 vicii_store(i, 0);
570 }
571 } else {
572 vicii.extended_enable = 1;
573 vicii.extended_lockout = 0;
574 for (i = 0; i <= 0x3e; i++) {
575 vicii_store(i, 0);
576 }
577 vicii_store(0x36, 0x76);
578 for (i = 0x40; i <= 0x4f; i++) {
579 vicii_store(i, 0);
580 }
581 vicii_store(0x3f, 0);
582 }
583 raster_sprite_status_reset(vicii.raster.sprite_status, vicii_sprite_offset());
584 }
585
586 /* This /should/ put the VIC-II in the same state as after a powerup, if
587 `reset_vicii()' is called afterwards. But FIXME, as we are not really
588 emulating everything correctly here; just $D011. */
vicii_powerup(void)589 void vicii_powerup(void)
590 {
591 memset(vicii.regs, 0, sizeof(vicii.regs));
592
593 vicii.irq_status = 0;
594 vicii.raster_irq_line = 0;
595 vicii.raster_irq_clk = 1;
596 vicii.ram_base_phi1 = mem_ram;
597 vicii.ram_base_phi2 = mem_ram;
598
599 vicii.vaddr_mask_phi1 = 0xffff;
600 vicii.vaddr_mask_phi2 = 0xffff;
601 vicii.vaddr_offset_phi1 = 0;
602 vicii.vaddr_offset_phi2 = 0;
603
604 vicii.allow_bad_lines = 0;
605 vicii.sprite_sprite_collisions = vicii.sprite_background_collisions = 0;
606 vicii.fetch_idx = VICII_FETCH_MATRIX;
607 vicii.idle_state = 0;
608 vicii.force_display_state = 0;
609 vicii.memory_fetch_done = 0;
610 vicii.memptr = 0;
611 vicii.mem_counter = 0;
612 vicii.mem_counter_inc = 0;
613 vicii.bad_line = 0;
614 vicii.ycounter_reset_checked = 0;
615 vicii.force_black_overscan_background_color = 0;
616 vicii.light_pen.state = 0;
617 vicii.light_pen.x = vicii.light_pen.y = vicii.light_pen.x_extra_bits = vicii.light_pen.triggered = 0;
618 vicii.vbank_phi1 = 0;
619 vicii.vbank_phi2 = 0;
620 /* vicii.vbank_ptr = ram; */
621 vicii.idle_data = 0;
622 vicii.idle_data_location = IDLE_NONE;
623 vicii.last_emulate_line_clk = 0;
624
625 vicii_reset();
626
627 vicii.raster.blank = 1;
628 vicii.raster.display_ystart = vicii.row_24_start_line;
629 vicii.raster.display_ystop = vicii.row_24_stop_line;
630
631 vicii.raster.ysmooth = 0;
632 }
633
634 /* ---------------------------------------------------------------------*/
635
636 /* This hook is called whenever video bank must be changed. */
vicii_set_vbanks(int vbank_p1,int vbank_p2)637 static inline void vicii_set_vbanks(int vbank_p1, int vbank_p2)
638 {
639 /* Warning: assumes it's called within a memory write access.
640 FIXME: Change name? */
641 /* Also, we assume the bank has *really* changed, and do not do any
642 special optimizations for the not-really-changed case. */
643 vicii_handle_pending_alarms(maincpu_rmw_flag + 1);
644 if (maincpu_clk >= vicii.draw_clk) {
645 vicii_raster_draw_alarm_handler(maincpu_clk - vicii.draw_clk, NULL);
646 }
647
648 vicii.vbank_phi1 = vbank_p1;
649 vicii.vbank_phi2 = vbank_p2;
650 vicii_update_memory_ptrs(VICII_RASTER_CYCLE(maincpu_clk));
651 }
652
653 /* Phi1 and Phi2 accesses */
vicii_set_vbank(int num_vbank)654 void vicii_set_vbank(int num_vbank)
655 {
656 int tmp = num_vbank << 14;
657 vicii_set_vbanks(tmp, tmp);
658 }
659
660 /* Phi1 accesses */
vicii_set_phi1_vbank(int num_vbank)661 void vicii_set_phi1_vbank(int num_vbank)
662 {
663 vicii_set_vbanks(num_vbank << 14, vicii.vbank_phi2);
664 }
665
666 /* Phi2 accesses */
vicii_set_phi2_vbank(int num_vbank)667 void vicii_set_phi2_vbank(int num_vbank)
668 {
669 vicii_set_vbanks(vicii.vbank_phi1, num_vbank << 14);
670 }
671
672 /* ---------------------------------------------------------------------*/
673
674 /* Set light pen input state. */
vicii_set_light_pen(CLOCK mclk,int state)675 void vicii_set_light_pen(CLOCK mclk, int state)
676 {
677 if (state) {
678 vicii_trigger_light_pen(mclk);
679 }
680 vicii.light_pen.state = state;
681 }
682
683 /* Trigger the light pen. */
vicii_trigger_light_pen(CLOCK mclk)684 void vicii_trigger_light_pen(CLOCK mclk)
685 {
686 if (!vicii.light_pen.triggered) {
687 vicii.light_pen.triggered = 1;
688 vicii.light_pen.x = VICII_RASTER_X(mclk % vicii.cycles_per_line) - vicii.screen_leftborderwidth + 0x20;
689
690 if (vicii.light_pen.x < 0) {
691 vicii.light_pen.x = vicii.sprite_wrap_x + vicii.light_pen.x;
692 }
693
694 /* FIXME: why `+2'? */
695 vicii.light_pen.x = vicii.light_pen.x / 2 + 2 + vicii.light_pen.x_extra_bits;
696 vicii.light_pen.x_extra_bits = 0;
697 vicii.light_pen.y = VICII_RASTER_Y(mclk);
698
699 vicii_irq_lightpen_set(mclk);
700 }
701 }
702
703 /* Calculate lightpen pulse time based on x/y */
vicii_lightpen_timing(int x,int y)704 CLOCK vicii_lightpen_timing(int x, int y)
705 {
706 CLOCK pulse_time = maincpu_clk;
707
708 x += 0x80 - vicii.screen_leftborderwidth;
709 y += vicii.first_displayed_line;
710
711 /* Check if x would wrap to previous line */
712 if (x < 104) {
713 /* lightpen is off screen */
714 pulse_time = 0;
715 } else {
716 pulse_time += (x / 8) + (y * vicii.cycles_per_line);
717 /* Remove frame alarm jitter */
718 pulse_time -= maincpu_clk - VICII_LINE_START_CLK(maincpu_clk);
719
720 /* Store x extra bits for sub CLK precision */
721 vicii.light_pen.x_extra_bits = (x >> 1) & 0x3;
722 }
723
724 return pulse_time;
725 }
726
727 /* Change the base of RAM seen by the VIC-II. */
vicii_set_ram_bases(uint8_t * base_p1,uint8_t * base_p2)728 static inline void vicii_set_ram_bases(uint8_t *base_p1, uint8_t *base_p2)
729 {
730 /* WARNING: assumes `maincpu_rmw_flag' is 0 or 1. */
731 vicii_handle_pending_alarms(maincpu_rmw_flag + 1);
732
733 vicii.ram_base_phi1 = base_p1;
734 vicii.ram_base_phi2 = base_p2;
735 vicii_update_memory_ptrs(VICII_RASTER_CYCLE(maincpu_clk));
736 }
737
vicii_set_ram_base(uint8_t * base)738 void vicii_set_ram_base(uint8_t *base)
739 {
740 vicii_set_ram_bases(base, base);
741 }
742
vicii_set_phi1_ram_base(uint8_t * base)743 void vicii_set_phi1_ram_base(uint8_t *base)
744 {
745 vicii_set_ram_bases(base, vicii.ram_base_phi2);
746 }
747
vicii_set_phi2_ram_base(uint8_t * base)748 void vicii_set_phi2_ram_base(uint8_t *base)
749 {
750 vicii_set_ram_bases(vicii.ram_base_phi1, base);
751 }
752
753
vicii_update_memory_ptrs_external(void)754 void vicii_update_memory_ptrs_external(void)
755 {
756 if (vicii.initialized > 0) {
757 vicii_update_memory_ptrs(VICII_RASTER_CYCLE(maincpu_clk));
758 }
759 }
760
761 /* Set the memory pointers according to the values in the registers. */
vicii_update_memory_ptrs(unsigned int cycle)762 void vicii_update_memory_ptrs(unsigned int cycle)
763 {
764 /* FIXME: This is *horrible*! */
765 static uint8_t *old_screen_ptr, *old_bitmap_low_ptr, *old_bitmap_high_ptr;
766 static uint8_t *old_chargen_ptr;
767 static int old_vbank_p1 = -1;
768 static int old_vbank_p2 = -1;
769 uint16_t screen_addr; /* Screen start address. */
770 uint8_t *char_base; /* Pointer to character memory. */
771 uint8_t *bitmap_low_base; /* Pointer to bitmap memory (low part). */
772 uint8_t *bitmap_high_base; /* Pointer to bitmap memory (high part). */
773 int tmp, bitmap_bank;
774
775 if (vicii.viciidtv) {
776 viciidtv_update_colorram();
777 }
778
779 screen_addr = vicii.vbank_phi2 + ((vicii.regs[0x18] & 0xf0) << 6);
780
781 screen_addr = (screen_addr & vicii.vaddr_mask_phi2)
782 | vicii.vaddr_offset_phi2;
783
784 VICII_DEBUG_REGISTER(("Screen memory at $%04X", screen_addr));
785
786 tmp = (vicii.regs[0x18] & 0xe) << 10;
787 tmp = (tmp + vicii.vbank_phi1);
788 tmp &= vicii.vaddr_mask_phi1;
789 tmp |= vicii.vaddr_offset_phi1;
790
791 bitmap_bank = tmp & 0xe000;
792 bitmap_low_base = vicii.ram_base_phi1 + bitmap_bank;
793
794 VICII_DEBUG_REGISTER(("Bitmap memory at $%04X", tmp & 0xe000));
795
796 if (export.ultimax_phi2 != 0) {
797 /* phi2 fetch from expansion port in ultimax mode */
798 #if 0
799 if ((screen_addr & 0x3fff) >= 0x3000) {
800 /* vicii.screen_base_phi2 = romh_banks + (romh_bank << 13)
801 + (screen_addr & 0xfff) + 0x1000; */
802 vicii.screen_base_phi2 = ultimax_romh_phi2_ptr((uint16_t)(0x1000 + (screen_addr & 0xfff)));
803 } else {
804 vicii.screen_base_phi2 = vicii.ram_base_phi2 + screen_addr;
805 }
806 #endif
807 uint8_t *ptr;
808 if ((ptr = ultimax_romh_phi2_ptr((uint16_t)(0x1000 + (screen_addr & 0xfff))))) {
809 if ((screen_addr & 0x3fff) >= 0x3000) {
810 vicii.screen_base_phi2 = ptr;
811 } else {
812 vicii.screen_base_phi2 = vicii.ram_base_phi2 + screen_addr;
813 }
814 } else {
815 goto phi2noultimax;
816 }
817 } else {
818 phi2noultimax:
819 if ((screen_addr & vicii.vaddr_chargen_mask_phi2)
820 != vicii.vaddr_chargen_value_phi2) {
821 vicii.screen_base_phi2 = vicii.ram_base_phi2 + screen_addr;
822 } else {
823 vicii.screen_base_phi2 = mem_chargen_rom_ptr
824 + (screen_addr & 0xc00);
825 }
826 }
827
828 if (export.ultimax_phi1 != 0) {
829 /* phi1 fetch from expansion port in ultimax mode */
830 #if 0
831 if ((screen_addr & 0x3fff) >= 0x3000) {
832 /* vicii.screen_base_phi1 = romh_banks + (romh_bank << 13)
833 + (screen_addr & 0xfff) + 0x1000; */
834 vicii.screen_base_phi1 = ultimax_romh_phi1_ptr((uint16_t)(0x1000 + (screen_addr & 0xfff)));
835 } else {
836 vicii.screen_base_phi1 = vicii.ram_base_phi1 + screen_addr;
837 }
838 #endif
839 uint8_t *ptr;
840 if ((ptr = ultimax_romh_phi1_ptr((uint16_t)(0x1000 + (screen_addr & 0xfff))))) {
841 if ((screen_addr & 0x3fff) >= 0x3000) {
842 vicii.screen_base_phi1 = ptr;
843 } else {
844 vicii.screen_base_phi1 = vicii.ram_base_phi1 + screen_addr;
845 }
846 } else {
847 goto phi1noultimax;
848 }
849 if ((tmp & 0x3fff) >= 0x3000) {
850 /* char_base = romh_banks + (romh_bank << 13) + (tmp & 0xfff) + 0x1000; */
851 char_base = ultimax_romh_phi1_ptr((uint16_t)(0x1000 + (tmp & 0xfff)));
852 } else {
853 char_base = vicii.ram_base_phi1 + tmp;
854 }
855
856 if (((bitmap_bank + 0x1000) & 0x3fff) >= 0x3000) {
857 /* bitmap_high_base = romh_banks + (romh_bank << 13) + 0x1000; */
858 bitmap_high_base = ultimax_romh_phi1_ptr(0x1000);
859 } else {
860 bitmap_high_base = bitmap_low_base + 0x1000;
861 }
862 } else {
863 phi1noultimax:
864 if ((screen_addr & vicii.vaddr_chargen_mask_phi1) != vicii.vaddr_chargen_value_phi1) {
865 vicii.screen_base_phi1 = vicii.ram_base_phi1 + screen_addr;
866 } else {
867 vicii.screen_base_phi1 = mem_chargen_rom_ptr + (screen_addr & 0xc00);
868 }
869
870 if ((tmp & vicii.vaddr_chargen_mask_phi1) != vicii.vaddr_chargen_value_phi1) {
871 char_base = vicii.ram_base_phi1 + tmp;
872 } else {
873 char_base = mem_chargen_rom_ptr + (tmp & 0x0800);
874 }
875
876 if (((bitmap_bank + 0x1000) & vicii.vaddr_chargen_mask_phi1) != vicii.vaddr_chargen_value_phi1) {
877 bitmap_high_base = bitmap_low_base + 0x1000;
878 } else {
879 bitmap_high_base = mem_chargen_rom_ptr;
880 }
881 }
882
883 if (vicii.viciidtv) {
884 switch (vicii.video_mode) {
885 /* TODO other modes */
886 case VICII_8BPP_PIXEL_CELL_MODE:
887 case VICII_ILLEGAL_LINEAR_MODE:
888 vicii.screen_base_phi2 = vicii.ram_base_phi2 + (vicii.regs[0x45] << 16) + (vicii.regs[0x3b] << 8) + vicii.regs[0x3a];
889 break;
890 default:
891 vicii.screen_base_phi2 += (vicii.regs[0x45] << 16);
892 char_base += (vicii.regs[0x3d] << 16);
893 bitmap_low_base += (vicii.regs[0x3d] << 16);
894 bitmap_high_base += (vicii.regs[0x3d] << 16);
895 break;
896 }
897 }
898
899 tmp = VICII_RASTER_CHAR(cycle);
900
901 if (vicii.idle_data_location != IDLE_NONE &&
902 old_vbank_p2 != vicii.vbank_phi2) {
903 if (vicii.idle_data_location == IDLE_39FF) {
904 raster_changes_foreground_add_int(&vicii.raster,
905 VICII_RASTER_CHAR(cycle),
906 &vicii.idle_data,
907 vicii.ram_base_phi2[vicii.vbank_phi2
908 + 0x39ff]);
909 } else {
910 raster_changes_foreground_add_int(&vicii.raster,
911 VICII_RASTER_CHAR(cycle),
912 &vicii.idle_data,
913 vicii.ram_base_phi2[vicii.vbank_phi2
914 + 0x3fff]);
915 }
916 }
917
918 if (tmp <= 0 && maincpu_clk < vicii.draw_clk) {
919 old_screen_ptr = vicii.screen_ptr = vicii.screen_base_phi2;
920 old_bitmap_low_ptr = vicii.bitmap_low_ptr = bitmap_low_base;
921 old_bitmap_high_ptr = vicii.bitmap_high_ptr = bitmap_high_base;
922 old_chargen_ptr = vicii.chargen_ptr = char_base;
923 old_vbank_p1 = vicii.vbank_phi1;
924 old_vbank_p2 = vicii.vbank_phi2;
925 /* vicii.vbank_ptr = vicii.ram_base + vicii.vbank; */
926 } else if (tmp < VICII_SCREEN_TEXTCOLS) {
927 if (vicii.screen_base_phi2 != old_screen_ptr) {
928 raster_changes_foreground_add_ptr(&vicii.raster, tmp,
929 (void *)&vicii.screen_ptr,
930 (void *)vicii.screen_base_phi2);
931 old_screen_ptr = vicii.screen_base_phi2;
932 }
933
934 if (bitmap_low_base != old_bitmap_low_ptr) {
935 raster_changes_foreground_add_ptr(&vicii.raster,
936 tmp,
937 (void *)&vicii.bitmap_low_ptr,
938 (void *)(bitmap_low_base));
939 old_bitmap_low_ptr = bitmap_low_base;
940 }
941
942 if (bitmap_high_base != old_bitmap_high_ptr) {
943 raster_changes_foreground_add_ptr(&vicii.raster,
944 tmp,
945 (void *)&vicii.bitmap_high_ptr,
946 (void *)(bitmap_high_base));
947 old_bitmap_high_ptr = bitmap_high_base;
948 }
949
950 if (char_base != old_chargen_ptr) {
951 raster_changes_foreground_add_ptr(&vicii.raster,
952 tmp,
953 (void *)&vicii.chargen_ptr,
954 (void *)char_base);
955 old_chargen_ptr = char_base;
956 }
957
958 if (vicii.vbank_phi1 != old_vbank_p1) {
959 old_vbank_p1 = vicii.vbank_phi1;
960 }
961
962 if (vicii.vbank_phi2 != old_vbank_p2) {
963 old_vbank_p2 = vicii.vbank_phi2;
964 }
965 } else {
966 if (vicii.screen_base_phi2 != old_screen_ptr) {
967 raster_changes_next_line_add_ptr(&vicii.raster,
968 (void *)&vicii.screen_ptr,
969 (void *)vicii.screen_base_phi2);
970 old_screen_ptr = vicii.screen_base_phi2;
971 }
972
973 if (bitmap_low_base != old_bitmap_low_ptr) {
974 raster_changes_next_line_add_ptr(&vicii.raster,
975 (void *)&vicii.bitmap_low_ptr,
976 (void *)(bitmap_low_base));
977 old_bitmap_low_ptr = bitmap_low_base;
978 }
979
980 if (bitmap_high_base != old_bitmap_high_ptr) {
981 raster_changes_next_line_add_ptr(&vicii.raster,
982 (void *)&vicii.bitmap_high_ptr,
983 (void *)(bitmap_high_base));
984 old_bitmap_high_ptr = bitmap_high_base;
985 }
986
987 if (char_base != old_chargen_ptr) {
988 raster_changes_next_line_add_ptr(&vicii.raster,
989 (void *)&vicii.chargen_ptr,
990 (void *)char_base);
991 old_chargen_ptr = char_base;
992 }
993
994 if (vicii.vbank_phi1 != old_vbank_p1) {
995 old_vbank_p1 = vicii.vbank_phi1;
996 }
997
998 if (vicii.vbank_phi2 != old_vbank_p2) {
999 old_vbank_p2 = vicii.vbank_phi2;
1000 }
1001 }
1002 }
1003
1004 /* Set the video mode according to the values in registers $D011 and $D016 of
1005 the VIC-II chip. */
vicii_update_video_mode(unsigned int cycle)1006 void vicii_update_video_mode(unsigned int cycle)
1007 {
1008 int new_video_mode;
1009
1010 new_video_mode = ((vicii.regs[0x11] & 0x60) | (vicii.regs[0x16] & 0x10)) >> 4;
1011
1012 if (vicii.viciidtv) {
1013 new_video_mode |= (((vicii.regs[0x3c] & 0x04) << 1) | ((vicii.regs[0x3c] & 0x01) << 3));
1014
1015 if (((new_video_mode) == VICII_8BPP_FRED_MODE) && ((vicii.regs[0x3c] & 0x04) == 0)) {
1016 new_video_mode = VICII_8BPP_FRED2_MODE;
1017 }
1018
1019 if (((new_video_mode) == VICII_8BPP_CHUNKY_MODE) && ((vicii.regs[0x3c] & 0x10) == 0)) {
1020 if (vicii.regs[0x3c] & 0x04) {
1021 new_video_mode = VICII_8BPP_PIXEL_CELL_MODE;
1022 } else {
1023 new_video_mode = VICII_ILLEGAL_LINEAR_MODE;
1024 }
1025 }
1026
1027 /* HACK to make vcache display gfx in chunky & the rest */
1028 if ((new_video_mode >= VICII_8BPP_CHUNKY_MODE) && (new_video_mode <= VICII_8BPP_PIXEL_CELL_MODE)) {
1029 vicii.raster.dont_cache = 1;
1030 }
1031
1032 viciidtv_update_colorram();
1033 }
1034
1035 if (new_video_mode != vicii.video_mode) {
1036 switch (new_video_mode) {
1037 case VICII_ILLEGAL_TEXT_MODE:
1038 case VICII_ILLEGAL_BITMAP_MODE_1:
1039 case VICII_ILLEGAL_BITMAP_MODE_2:
1040 case VICII_ILLEGAL_LINEAR_MODE:
1041 /* Force the overscan color to black. */
1042 raster_changes_background_add_int
1043 (&vicii.raster, VICII_RASTER_X(cycle),
1044 &vicii.raster.idle_background_color, 0);
1045 raster_changes_background_add_int
1046 (&vicii.raster,
1047 VICII_RASTER_X(VICII_RASTER_CYCLE(maincpu_clk)),
1048 &vicii.raster.xsmooth_color, 0);
1049 vicii.get_background_from_vbuf = 0;
1050 vicii.force_black_overscan_background_color = 1;
1051 break;
1052 case VICII_HIRES_BITMAP_MODE:
1053 raster_changes_background_add_int
1054 (&vicii.raster, VICII_RASTER_X(cycle),
1055 &vicii.raster.idle_background_color, 0);
1056 raster_changes_background_add_int
1057 (&vicii.raster,
1058 VICII_RASTER_X(VICII_RASTER_CYCLE(maincpu_clk)),
1059 &vicii.raster.xsmooth_color,
1060 vicii.background_color_source & 0x0f);
1061 vicii.get_background_from_vbuf = VICII_HIRES_BITMAP_MODE;
1062 vicii.force_black_overscan_background_color = 1;
1063 break;
1064 case VICII_EXTENDED_TEXT_MODE:
1065 raster_changes_background_add_int
1066 (&vicii.raster, VICII_RASTER_X(cycle),
1067 &vicii.raster.idle_background_color,
1068 vicii.viciidtv ? vicii.dtvpalette[vicii.regs[0x21]] : vicii.regs[0x21]);
1069 raster_changes_background_add_int
1070 (&vicii.raster,
1071 VICII_RASTER_X(VICII_RASTER_CYCLE(maincpu_clk)),
1072 &vicii.raster.xsmooth_color,
1073 vicii.viciidtv ? vicii.dtvpalette[vicii.regs[0x21 + (vicii.background_color_source >> 6)]] : vicii.regs[0x21 + (vicii.background_color_source >> 6)]);
1074 vicii.get_background_from_vbuf = VICII_EXTENDED_TEXT_MODE;
1075 vicii.force_black_overscan_background_color = 0;
1076 break;
1077 default:
1078 /* The overscan background color is given by the background
1079 color register. */
1080 raster_changes_background_add_int
1081 (&vicii.raster, VICII_RASTER_X(cycle),
1082 &vicii.raster.idle_background_color,
1083 vicii.viciidtv ? vicii.dtvpalette[vicii.regs[0x21]] : vicii.regs[0x21]);
1084 raster_changes_background_add_int
1085 (&vicii.raster,
1086 VICII_RASTER_X(VICII_RASTER_CYCLE(maincpu_clk)),
1087 &vicii.raster.xsmooth_color,
1088 vicii.viciidtv ? vicii.dtvpalette[vicii.regs[0x21]] : vicii.regs[0x21]);
1089 vicii.get_background_from_vbuf = 0;
1090 vicii.force_black_overscan_background_color = 0;
1091 break;
1092 }
1093
1094 {
1095 int pos;
1096
1097 pos = VICII_RASTER_CHAR(cycle) - 1;
1098
1099 raster_changes_background_add_int(&vicii.raster,
1100 VICII_RASTER_X(cycle),
1101 &vicii.raster.video_mode,
1102 new_video_mode);
1103
1104 raster_changes_foreground_add_int(&vicii.raster, pos,
1105 &vicii.raster.last_video_mode,
1106 vicii.video_mode);
1107
1108 raster_changes_foreground_add_int(&vicii.raster, pos,
1109 &vicii.raster.video_mode,
1110 new_video_mode);
1111
1112 if (vicii.idle_data_location != IDLE_NONE) {
1113 if (vicii.regs[0x11] & 0x40) {
1114 raster_changes_foreground_add_int
1115 (&vicii.raster, pos + 1, (void *)&vicii.idle_data,
1116 vicii.ram_base_phi2[vicii.vbank_phi2 + 0x39ff]);
1117 } else {
1118 raster_changes_foreground_add_int
1119 (&vicii.raster, pos + 1, (void *)&vicii.idle_data,
1120 vicii.ram_base_phi2[vicii.vbank_phi2 + 0x3fff]);
1121 }
1122 }
1123
1124 raster_changes_foreground_add_int(&vicii.raster, pos + 2,
1125 &vicii.raster.last_video_mode,
1126 -1);
1127 }
1128
1129 vicii.video_mode = new_video_mode;
1130 }
1131
1132 #ifdef VICII_VMODE_DEBUG
1133 switch (new_video_mode) {
1134 case VICII_NORMAL_TEXT_MODE:
1135 VICII_DEBUG_VMODE(("Standard Text"));
1136 break;
1137 case VICII_MULTICOLOR_TEXT_MODE:
1138 VICII_DEBUG_VMODE(("Multicolor Text"));
1139 break;
1140 case VICII_HIRES_BITMAP_MODE:
1141 VICII_DEBUG_VMODE(("Hires Bitmap"));
1142 break;
1143 case VICII_MULTICOLOR_BITMAP_MODE:
1144 VICII_DEBUG_VMODE(("Multicolor Bitmap"));
1145 break;
1146 case VICII_EXTENDED_TEXT_MODE:
1147 VICII_DEBUG_VMODE(("Extended Text"));
1148 break;
1149 case VICII_ILLEGAL_TEXT_MODE:
1150 VICII_DEBUG_VMODE(("Illegal Text"));
1151 break;
1152 case VICII_ILLEGAL_BITMAP_MODE_1:
1153 VICII_DEBUG_VMODE(("Invalid Bitmap"));
1154 break;
1155 case VICII_ILLEGAL_BITMAP_MODE_2:
1156 VICII_DEBUG_VMODE(("Invalid Bitmap"));
1157 break;
1158 case VICII_8BPP_NORMAL_TEXT_MODE:
1159 VICII_DEBUG_VMODE(("8BPP Standard Text"));
1160 break;
1161 case VICII_8BPP_MULTICOLOR_TEXT_MODE:
1162 VICII_DEBUG_VMODE(("8BPP Multicolor Text"));
1163 break;
1164 case VICII_8BPP_HIRES_BITMAP_MODE:
1165 VICII_DEBUG_VMODE(("8BPP Hires Bitmap (?)"));
1166 break;
1167 case VICII_8BPP_MULTICOLOR_BITMAP_MODE:
1168 VICII_DEBUG_VMODE(("8BPP Multicolor Bitmap"));
1169 break;
1170 case VICII_8BPP_EXTENDED_TEXT_MODE:
1171 VICII_DEBUG_VMODE(("8BPP Extended Text"));
1172 break;
1173 case VICII_8BPP_CHUNKY_MODE:
1174 VICII_DEBUG_VMODE(("Chunky mode"));
1175 break;
1176 case VICII_8BPP_TWO_PLANE_BITMAP_MODE:
1177 VICII_DEBUG_VMODE(("Two plane bitmap"));
1178 break;
1179 case VICII_8BPP_FRED_MODE:
1180 VICII_DEBUG_VMODE(("FRED"));
1181 break;
1182 case VICII_8BPP_FRED2_MODE:
1183 VICII_DEBUG_VMODE(("FRED2"));
1184 break;
1185 case VICII_8BPP_PIXEL_CELL_MODE:
1186 VICII_DEBUG_VMODE(("8BPP Pixel Cell"));
1187 break;
1188 case VICII_ILLEGAL_LINEAR_MODE:
1189 VICII_DEBUG_VMODE(("Illegal Linear"));
1190 break;
1191 default: /* cannot happen */
1192 VICII_DEBUG_VMODE(("???"));
1193 }
1194
1195 VICII_DEBUG_VMODE(("Mode enabled at line $%04X, cycle %d.",
1196 VICII_RASTER_Y(maincpu_clk), cycle));
1197 #endif
1198 }
1199
1200 /* Redraw the current raster line. This happens at cycle VICII_DRAW_CYCLE
1201 of each line. */
vicii_raster_draw_alarm_handler(CLOCK offset,void * data)1202 void vicii_raster_draw_alarm_handler(CLOCK offset, void *data)
1203 {
1204 uint8_t prev_sprite_sprite_collisions;
1205 uint8_t prev_sprite_background_collisions;
1206 int in_visible_area;
1207
1208 prev_sprite_sprite_collisions = vicii.sprite_sprite_collisions;
1209 prev_sprite_background_collisions = vicii.sprite_background_collisions;
1210
1211 /* if the current line is between first and last displayed line, it is visible */
1212 /* additionally we must make sure not to skip lines within the range of active
1213 DMA, or certain effects will break in "no border" mode (see bug #3601657) */
1214 in_visible_area = (vicii.raster.current_line
1215 >= ((vicii.first_dma_line < (unsigned int)vicii.first_displayed_line) ? vicii.first_dma_line : vicii.first_displayed_line))
1216 && (vicii.raster.current_line
1217 <= (((vicii.last_dma_line + 7) > (unsigned int)vicii.last_displayed_line) ? (vicii.last_dma_line + 7) : vicii.last_displayed_line));
1218
1219 /* handle wrap if the first few lines are displayed in the visible lower border */
1220 if ((unsigned int)vicii.last_displayed_line >= vicii.screen_height) {
1221 in_visible_area |= vicii.raster.current_line
1222 <= ((unsigned int)vicii.last_displayed_line - vicii.screen_height);
1223 }
1224
1225 vicii.raster.xsmooth_shift_left = 0;
1226
1227 vicii_sprites_reset_xshift();
1228
1229 raster_line_emulate(&vicii.raster);
1230
1231 #if 0
1232 if (vicii.raster.current_line >= 60 && vicii.raster.current_line <= 60) {
1233 char buf[1000];
1234 int j, i;
1235 for (i = 0; i < 8; i++) {
1236 memset(buf, 0, sizeof(buf));
1237 for (j = 0; j < 40; j++) {
1238 sprintf(&buf[strlen(buf)], "%02x",
1239 vicii.raster.draw_buffer_ptr[vicii.raster.xsmooth
1240 + vicii.raster.geometry->gfx_position.x + i * 40 + j]);
1241 }
1242 log_debug(buf);
1243 }
1244 }
1245 #endif
1246
1247 if (vicii.raster.current_line == 0) {
1248 /* no vsync here for NTSC */
1249 if ((unsigned int)vicii.last_displayed_line < vicii.screen_height) {
1250 raster_skip_frame(&vicii.raster,
1251 vsync_do_vsync(vicii.raster.canvas,
1252 vicii.raster.skip_frame));
1253 }
1254 vicii.memptr = 0;
1255 vicii.mem_counter = 0;
1256 vicii.light_pen.triggered = 0;
1257
1258 if (vicii.light_pen.state) {
1259 vicii_trigger_light_pen(maincpu_clk);
1260 }
1261
1262 vicii.raster.blank_off = 0;
1263
1264 if (vicii.viciidtv) {
1265 memset(vicii.cbuf, 0, sizeof(vicii.cbuf));
1266
1267 /* Scheduled Blitter */
1268 if (blitter_on_irq & 0x40) {
1269 c64dtvblitter_trigger_blitter();
1270 }
1271 /* Scheduled DMA */
1272 if (dma_on_irq & 0x40) {
1273 c64dtvdma_trigger_dma();
1274 }
1275
1276 /* HACK to make vcache display gfx in chunky & the rest */
1277 if ((vicii.video_mode >= VICII_8BPP_CHUNKY_MODE) &&
1278 (vicii.video_mode <= VICII_8BPP_PIXEL_CELL_MODE)) {
1279 vicii.raster.dont_cache = 1;
1280 }
1281
1282 /* HACK to fix greetings in 2008 */
1283 if (vicii.video_mode == VICII_8BPP_PIXEL_CELL_MODE) {
1284 vicii_update_memory_ptrs(VICII_RASTER_CYCLE(maincpu_clk));
1285 }
1286 }
1287
1288 }
1289
1290 /* vsync for NTSC */
1291 if ((unsigned int)vicii.last_displayed_line >= vicii.screen_height
1292 && vicii.raster.current_line == vicii.last_displayed_line - vicii.screen_height + 1) {
1293 raster_skip_frame(&vicii.raster,
1294 vsync_do_vsync(vicii.raster.canvas,
1295 vicii.raster.skip_frame));
1296 }
1297
1298 if (vicii.viciidtv) {
1299 if ((!vicii.overscan && vicii.raster.current_line == 48) || (vicii.overscan && vicii.raster.current_line == 10)) {
1300 vicii.counta = vicii.regs[0x3a] + (vicii.regs[0x3b] << 8) + (vicii.regs[0x45] << 16);
1301
1302 vicii.countb = vicii.regs[0x49] + (vicii.regs[0x4a] << 8) + (vicii.regs[0x4b] << 16);
1303 }
1304 }
1305
1306 if (in_visible_area) {
1307 if (!vicii.idle_state) {
1308 vicii.mem_counter = (vicii.mem_counter + vicii.mem_counter_inc) & 0x3ff;
1309 }
1310 vicii.mem_counter_inc = VICII_SCREEN_TEXTCOLS;
1311
1312 if (vicii.viciidtv && !vicii.idle_state) {
1313 /* TODO should be done in cycle 57 */
1314 if (!(VICII_MODULO_BUG(vicii.video_mode) && (vicii.raster.ycounter == 7))) {
1315 vicii.counta += vicii.counta_mod;
1316 vicii.countb += vicii.countb_mod;
1317 }
1318
1319 /* TODO hack */
1320 if (!vicii.overscan) {
1321 vicii.counta += vicii.counta_step * 40;
1322 vicii.countb += vicii.countb_step * 40;
1323 } else {
1324 /* faked overscan */
1325 vicii.counta += vicii.counta_step * 48;
1326 vicii.countb += vicii.countb_step * 48;
1327 }
1328
1329 /* HACK to fix greetings in 2008 */
1330 if ((vicii.video_mode == VICII_8BPP_PIXEL_CELL_MODE) && (vicii.raster.ycounter == 7)) {
1331 vicii.screen_base_phi2 += vicii.counta_mod;
1332 }
1333 }
1334
1335 /* `ycounter' makes the chip go to idle state when it reaches the
1336 maximum value. */
1337 if (vicii.raster.ycounter == 7) {
1338 vicii.idle_state = 1;
1339 vicii.memptr = vicii.mem_counter;
1340 }
1341 if (!vicii.idle_state || vicii.bad_line) {
1342 vicii.raster.ycounter = (vicii.raster.ycounter + 1) & 0x7;
1343 vicii.idle_state = 0;
1344 }
1345 if (vicii.force_display_state) {
1346 vicii.idle_state = 0;
1347 vicii.force_display_state = 0;
1348 }
1349 vicii.raster.draw_idle_state = vicii.idle_state;
1350 vicii.bad_line = 0;
1351 }
1352
1353 vicii.ycounter_reset_checked = 0;
1354 vicii.memory_fetch_done = 0;
1355 vicii.buf_offset = 0;
1356
1357 if (vicii.raster.current_line == vicii.first_dma_line) {
1358 vicii.allow_bad_lines = !vicii.raster.blank;
1359 }
1360
1361 /* As explained in Christian's article, only the first collision
1362 (i.e. the first time the collision register becomes non-zero) actually
1363 triggers an interrupt. */
1364 if (vicii_resources.sprite_sprite_collisions_enabled
1365 && vicii.raster.sprite_status->sprite_sprite_collisions != 0
1366 && !prev_sprite_sprite_collisions) {
1367 vicii_irq_sscoll_set();
1368 }
1369
1370 if (vicii_resources.sprite_background_collisions_enabled
1371 && vicii.raster.sprite_status->sprite_background_collisions
1372 && !prev_sprite_background_collisions) {
1373 vicii_irq_sbcoll_set();
1374 }
1375
1376 if (vicii.idle_state) {
1377 if (vicii.regs[0x11] & 0x40) {
1378 vicii.idle_data_location = IDLE_39FF;
1379 vicii.idle_data = vicii.ram_base_phi2[vicii.vbank_phi2 + 0x39ff];
1380 } else {
1381 vicii.idle_data_location = IDLE_3FFF;
1382 vicii.idle_data = vicii.ram_base_phi2[vicii.vbank_phi2 + 0x3fff];
1383 }
1384 } else {
1385 vicii.idle_data_location = IDLE_NONE;
1386 }
1387
1388 /* Set the next draw event. */
1389 vicii.last_emulate_line_clk += vicii.cycles_per_line;
1390 vicii.draw_clk = vicii.last_emulate_line_clk + vicii.draw_cycle;
1391 alarm_set(vicii.raster_draw_alarm, vicii.draw_clk);
1392 }
1393
vicii_set_canvas_refresh(int enable)1394 void vicii_set_canvas_refresh(int enable)
1395 {
1396 raster_set_canvas_refresh(&vicii.raster, enable);
1397 }
1398
vicii_shutdown(void)1399 void vicii_shutdown(void)
1400 {
1401 lib_free(vicii.idle_3fff);
1402 lib_free(vicii.idle_3fff_old);
1403 vicii_sprites_shutdown();
1404 raster_sprite_status_destroy(&vicii.raster);
1405 raster_shutdown(&vicii.raster);
1406 }
1407
vicii_screenshot(screenshot_t * screenshot)1408 void vicii_screenshot(screenshot_t *screenshot)
1409 {
1410 raster_screenshot(&vicii.raster, screenshot);
1411 screenshot->chipid = "VICII";
1412 screenshot->video_regs = vicii.regs;
1413 screenshot->screen_ptr = vicii.screen_base_phi2;
1414 screenshot->chargen_ptr = vicii.chargen_ptr;
1415 screenshot->bitmap_ptr = NULL;
1416 screenshot->bitmap_low_ptr = vicii.bitmap_low_ptr;
1417 screenshot->bitmap_high_ptr = vicii.bitmap_high_ptr;
1418 screenshot->color_ram_ptr = mem_color_ram_vicii;
1419 }
1420
vicii_async_refresh(struct canvas_refresh_s * refresh)1421 void vicii_async_refresh(struct canvas_refresh_s *refresh)
1422 {
1423 raster_async_refresh(&vicii.raster, refresh);
1424 }
1425
vicii_dump(void)1426 int vicii_dump(void)
1427 {
1428 int m_muco, m_disp, m_ext, v_bank, v_vram;
1429 int i, bits;
1430
1431 m_ext = ((vicii.regs[0x11] & 0x40) >> 6); /* 0 standard, 1 extended */
1432 m_muco = ((vicii.regs[0x16] & 0x10) >> 4); /* 0 hires, 1 multi */
1433 m_disp = ((vicii.regs[0x11] & 0x20) >> 5); /* 0 text, 1 bitmap */
1434
1435 v_bank = vicii.vbank_phi2;
1436
1437 mon_out("Rasterline: current: %d IRQ: %d\n", vicii.raster.current_line, vicii.raster_irq_line);
1438 mon_out("Display Mode:");
1439 mon_out(m_ext ? " Extended" : " Standard");
1440 mon_out(m_muco ? " Multi Color" : " Hires");
1441 mon_out(m_disp ? " Bitmap" : " Text");
1442 mon_out("\nColors: Border: %2d Background: %2d\n", vicii.regs[0x20], vicii.regs[0x21]);
1443 if (m_ext) {
1444 mon_out(" BGCol1: %2d BGCol2: %2d BGCol3: %2d\n", vicii.regs[0x22], vicii.regs[0x23], vicii.regs[0x24]);
1445 } else if (m_muco && !m_disp) {
1446 mon_out(" MuCol1: %2d MuCol2: %2d\n", vicii.regs[0x22], vicii.regs[0x23]);
1447 }
1448 mon_out("Scroll X/Y: %d/%d\n", vicii.regs[0x16] & 0x07, vicii.regs[0x11] & 0x07);
1449 mon_out("Screen Size: %d x %d\n", 39 + ((vicii.regs[0x16] >> 3) & 1), 24 + ((vicii.regs[0x11] >> 3) & 1));
1450
1451 mon_out("\nVIC Memory Bank: $%04x - $%04x\n", v_bank, v_bank + 0x3fff);
1452 v_vram = ((vicii.regs[0x18] >> 4) * 0x0400) + v_bank;
1453 mon_out("\nVideo Memory: $%04x\n", v_vram);
1454 if (m_disp) {
1455 mon_out("Bitmap Memory: $%04x\n", (((vicii.regs[0x18] >> 3) & 1) * 0x2000) + v_bank);
1456 } else {
1457 i = (((vicii.regs[0x18] >> 1) & 0x7) * 0x800) + v_bank;
1458 /* FIXME: how does cbm510 work ? */
1459 if (machine_class == VICE_MACHINE_C64 ||
1460 machine_class == VICE_MACHINE_C128 ||
1461 machine_class == VICE_MACHINE_C64DTV ||
1462 machine_class == VICE_MACHINE_C64SC ||
1463 machine_class == VICE_MACHINE_SCPU64) {
1464 /* $1x00 and $9x00 mapped to $dx00 */
1465 if ((( i >> 12) == 1 ) || (( i >> 12) == 9 )) {
1466 i = 0xd000 | (i & 0x0f00);
1467 }
1468 }
1469 mon_out("Character Set: $%04x\n", i);
1470 }
1471
1472 mon_out("\nSprites:");
1473 mon_out("\n Spr.0 Spr.1 Spr.2 Spr.3 Spr.4 Spr.5 Spr.6 Spr.7");
1474 mon_out("\nEnabled: ");
1475 bits = vicii.regs[0x15];
1476 for (i = 0; i < 8; i++) {
1477 mon_out(" %5s", (bits & 1) ? "yes" : "no");
1478 bits >>= 1;
1479 }
1480 mon_out("\nPointer: ");
1481 for (i = 0x3f8; i < 0x400; i++) {
1482 mon_out(" $%02x", vicii.screen_ptr[i]);
1483 }
1484 mon_out("\nAddress: ");
1485 for (i = 0x3f8; i < 0x400; i++) {
1486 mon_out(" $%04x", v_bank + (vicii.screen_ptr[i] * 0x40));
1487 }
1488 mon_out("\nX-Pos: ");
1489 bits = vicii.regs[0x10]; /* sprite x msb */
1490 for (i = 0; i < 8; i++) {
1491 mon_out(" %5d", vicii.regs[i << 1] + (256 * (bits & 1)));
1492 bits >>= 1;
1493 }
1494 mon_out("\nY-Pos: ");
1495 for (i = 0; i < 8; i++) {
1496 mon_out(" %5d", vicii.regs[1 + (i << 1)]);
1497 }
1498 mon_out("\nX-Expand:");
1499 bits = vicii.regs[0x1d];
1500 for (i = 0; i < 8; i++) {
1501 mon_out(" %5s", (bits & 1) ? "yes" : "no");
1502 bits >>= 1;
1503 }
1504 mon_out("\nY-Expand:");
1505 bits = vicii.regs[0x17];
1506 for (i = 0; i < 8; i++) {
1507 mon_out(" %5s", (bits & 1) ? "yes" : "no");
1508 bits >>= 1;
1509 }
1510 mon_out("\nPriority:");
1511 bits = vicii.regs[0x1b];
1512 for (i = 0; i < 8; i++) {
1513 mon_out(" %5s", (bits & 1) ? "bg" : "spr");
1514 bits >>= 1;
1515 }
1516 mon_out("\nMode: ");
1517 bits = vicii.regs[0x1c];
1518 for (i = 0; i < 8; i++) {
1519 mon_out(" %5s", (bits & 1) ? "muco" : "std");
1520 bits >>= 1;
1521 }
1522 mon_out("\nColor: ");
1523 for (i = 0; i < 8; i++) {
1524 mon_out(" %5d", vicii.regs[i + 0x27]);
1525 }
1526 if (vicii.regs[0x1c]) {
1527 mon_out("\nMulti Color 1: %d Multi Color 2: %d", vicii.regs[0x25], vicii.regs[0x26]);
1528 }
1529 mon_out("\n");
1530
1531 /*
1532 TODO:
1533
1534 Current Scanline: 11
1535 Raster IRQ Scanline: 311
1536 Enabled Interrupts: None
1537 Pending Interrupts: Raster
1538 */
1539 return 0;
1540 }
1541