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