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 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 #include "vice.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "videoarch.h"
35
36 #include "c64cart.h"
37 #include "c64cartmem.h"
38 #include "clkguard.h"
39 #include "lib.h"
40 #include "log.h"
41 #include "machine.h"
42 #include "maincpu.h"
43 #include "mem.h"
44 #include "monitor.h"
45 #include "raster-line.h"
46 #include "raster-modes.h"
47 #include "resources.h"
48 #include "screenshot.h"
49 #include "types.h"
50 #include "vicii-chip-model.h"
51 #include "vicii-cmdline-options.h"
52 #include "vicii-color.h"
53 #include "vicii-draw.h"
54 #include "vicii-draw-cycle.h"
55 #include "vicii-fetch.h"
56 #include "vicii-irq.h"
57 #include "vicii-mem.h"
58 #include "vicii-resources.h"
59 #include "vicii-timing.h"
60 #include "vicii.h"
61 #include "viciitypes.h"
62 #include "vsync.h"
63 #include "video.h"
64 #include "viewport.h"
65
66
vicii_set_phi1_addr_options(uint16_t mask,uint16_t offset)67 void vicii_set_phi1_addr_options(uint16_t mask, uint16_t offset)
68 {
69 vicii.vaddr_mask_phi1 = mask;
70 vicii.vaddr_offset_phi1 = offset;
71
72 VICII_DEBUG_REGISTER(("Set phi1 video addr mask=%04x, offset=%04x", mask, offset));
73 }
74
vicii_set_phi2_addr_options(uint16_t mask,uint16_t offset)75 void vicii_set_phi2_addr_options(uint16_t mask, uint16_t offset)
76 {
77 vicii.vaddr_mask_phi2 = mask;
78 vicii.vaddr_offset_phi2 = offset;
79
80 VICII_DEBUG_REGISTER(("Set phi2 video addr mask=%04x, offset=%04x", mask, offset));
81 }
82
vicii_set_phi1_chargen_addr_options(uint16_t mask,uint16_t value)83 void vicii_set_phi1_chargen_addr_options(uint16_t mask, uint16_t value)
84 {
85 vicii.vaddr_chargen_mask_phi1 = mask;
86 vicii.vaddr_chargen_value_phi1 = value;
87
88 VICII_DEBUG_REGISTER(("Set phi1 chargen addr mask=%04x, value=%04x", mask, value));
89 }
90
vicii_set_phi2_chargen_addr_options(uint16_t mask,uint16_t value)91 void vicii_set_phi2_chargen_addr_options(uint16_t mask, uint16_t value)
92 {
93 vicii.vaddr_chargen_mask_phi2 = mask;
94 vicii.vaddr_chargen_value_phi2 = value;
95
96 VICII_DEBUG_REGISTER(("Set phi2 chargen addr mask=%04x, value=%04x", mask, value));
97 }
98
vicii_set_chargen_addr_options(uint16_t mask,uint16_t value)99 void vicii_set_chargen_addr_options(uint16_t mask, uint16_t value)
100 {
101 vicii.vaddr_chargen_mask_phi1 = mask;
102 vicii.vaddr_chargen_value_phi1 = value;
103 vicii.vaddr_chargen_mask_phi2 = mask;
104 vicii.vaddr_chargen_value_phi2 = value;
105
106 VICII_DEBUG_REGISTER(("Set chargen addr mask=%04x, value=%04x", mask, value));
107 }
108
109 /* ---------------------------------------------------------------------*/
110
111 vicii_t vicii;
112
113 static void vicii_set_geometry(void);
114
clk_overflow_callback(CLOCK sub,void * unused_data)115 static void clk_overflow_callback(CLOCK sub, void *unused_data)
116 {
117 if (vicii.light_pen.trigger_cycle < CLOCK_MAX) {
118 vicii.light_pen.trigger_cycle -= sub;
119 }
120 }
121
vicii_change_timing(machine_timing_t * machine_timing,int border_mode)122 void vicii_change_timing(machine_timing_t *machine_timing, int border_mode)
123 {
124 vicii_timing_set(machine_timing, border_mode);
125
126 if (vicii.initialized) {
127 vicii_set_geometry();
128 raster_mode_change();
129 }
130 }
131
vicii_handle_pending_alarms_external(int num_write_cycles)132 void vicii_handle_pending_alarms_external(int num_write_cycles)
133 {
134 return;
135 }
136
vicii_handle_pending_alarms_external_write(void)137 void vicii_handle_pending_alarms_external_write(void)
138 {
139 return;
140 }
141
142 /* return pixel aspect ratio for current video mode
143 * based on http://codebase64.com/doku.php?id=base:pixel_aspect_ratio
144 */
vicii_get_pixel_aspect(void)145 static float vicii_get_pixel_aspect(void)
146 {
147 int video;
148 resources_get_int("MachineVideoStandard", &video);
149 switch (video) {
150 case MACHINE_SYNC_PAL:
151 return 0.93650794f;
152 case MACHINE_SYNC_PALN:
153 return 0.90769231f;
154 case MACHINE_SYNC_NTSC:
155 return 0.75000000f;
156 case MACHINE_SYNC_NTSCOLD:
157 return 0.76171875f;
158 default:
159 return 1.0f;
160 }
161 }
162
163 /* return type of monitor used for current video mode */
vicii_get_crt_type(void)164 static int vicii_get_crt_type(void)
165 {
166 int video;
167 resources_get_int("MachineVideoStandard", &video);
168 switch (video) {
169 case MACHINE_SYNC_PAL:
170 case MACHINE_SYNC_PALN:
171 return 1; /* PAL */
172 default:
173 return 0; /* NTSC */
174 }
175 }
176
vicii_set_geometry(void)177 static void vicii_set_geometry(void)
178 {
179 unsigned int width, height;
180
181 width = vicii.screen_leftborderwidth + VICII_SCREEN_XPIX + vicii.screen_rightborderwidth;
182 height = vicii.last_displayed_line - vicii.first_displayed_line + 1;
183
184 raster_set_geometry(&vicii.raster,
185 width, height, /* canvas dimensions */
186 width, vicii.screen_height, /* screen dimensions */
187 VICII_SCREEN_XPIX, VICII_SCREEN_YPIX, /* gfx dimensions */
188 VICII_SCREEN_TEXTCOLS, VICII_SCREEN_TEXTLINES, /* text dimensions */
189 vicii.screen_leftborderwidth, VICII_NO_BORDER_FIRST_DISPLAYED_LINE, /* gfx position */
190 0, /* gfx area doesn't move */
191 vicii.first_displayed_line,
192 vicii.last_displayed_line,
193 0, /* extra offscreen border left */
194 0) /* extra offscreen border right */;
195
196 vicii.raster.display_ystart = 0;
197 vicii.raster.display_ystop = vicii.screen_height;
198 vicii.raster.display_xstart = 0;
199 vicii.raster.display_xstop = width;
200 vicii.raster.dont_cache_all = 1;
201
202 vicii.raster.geometry->pixel_aspect_ratio = vicii_get_pixel_aspect();
203 vicii.raster.viewport->crt_type = vicii_get_crt_type();
204 }
205
init_raster(void)206 static int init_raster(void)
207 {
208 raster_t *raster;
209
210 raster = &vicii.raster;
211
212 raster->sprite_status = NULL;
213 raster_line_changes_init(raster);
214
215 /* We only use the dummy mode for "drawing" to raster.
216 Report only 1 video mode and set the idle mode to it. */
217 if (raster_init(raster, 1) < 0) {
218 return -1;
219 }
220 raster_modes_set_idle_mode(raster->modes, VICII_DUMMY_MODE);
221
222 resources_touch("VICIIVideoCache");
223
224 vicii_set_geometry();
225
226 if (vicii_color_update_palette(raster->canvas) < 0) {
227 log_error(vicii.log, "Cannot load palette.");
228 return -1;
229 }
230
231 #if 0
232 raster_set_title(raster, machine_name);
233 #else
234 /* hack */
235 if (machine_class != VICE_MACHINE_C64SC) {
236 raster_set_title(raster, machine_name);
237 } else {
238 raster_set_title(raster, "C64 (x64sc)");
239 }
240 #endif
241
242 if (raster_realize(raster) < 0) {
243 return -1;
244 }
245
246 return 0;
247 }
248
vicii_new_sprites_init(void)249 static void vicii_new_sprites_init(void)
250 {
251 int i;
252
253 for (i = 0; i < VICII_NUM_SPRITES; i++) {
254 vicii.sprite[i].data = 0;
255 vicii.sprite[i].mc = 0;
256 vicii.sprite[i].mcbase = 0;
257 vicii.sprite[i].pointer = 0;
258 vicii.sprite[i].exp_flop = 1;
259 vicii.sprite[i].x = 0;
260 }
261
262 vicii.sprite_display_bits = 0;
263 vicii.sprite_dma = 0;
264 }
265
266 /* Initialize the VIC-II emulation. */
vicii_init(unsigned int flag)267 raster_t *vicii_init(unsigned int flag)
268 {
269 if (flag != VICII_STANDARD) {
270 return NULL;
271 }
272
273 vicii.log = log_open("VIC-II");
274
275 vicii_chip_model_init();
276
277 vicii_irq_init();
278
279 if (init_raster() < 0) {
280 return NULL;
281 }
282
283 vicii_powerup();
284
285 vicii_draw_init();
286 vicii_draw_cycle_init();
287 vicii_new_sprites_init();
288
289 vicii.vmli = 0;
290
291 vicii.initialized = 1;
292
293 clk_guard_add_callback(maincpu_clk_guard, clk_overflow_callback, NULL);
294
295 return &vicii.raster;
296 }
297
vicii_get_canvas(void)298 struct video_canvas_s *vicii_get_canvas(void)
299 {
300 return vicii.raster.canvas;
301 }
302
303 /* Reset the VIC-II chip. */
vicii_reset(void)304 void vicii_reset(void)
305 {
306 raster_reset(&vicii.raster);
307
308 vicii.raster_line = 0;
309 vicii.raster_cycle = 6;
310 /* this should probably be updated through some function */
311 vicii.cycle_flags = 0;
312 vicii.start_of_frame = 0;
313 vicii.raster_irq_triggered = 0;
314
315 vicii.light_pen.state = 0;
316 vicii.light_pen.triggered = 0;
317 vicii.light_pen.x = vicii.light_pen.y = vicii.light_pen.x_extra_bits = 0;
318 vicii.light_pen.trigger_cycle = CLOCK_MAX;
319
320 /* Remove all the IRQ sources. */
321 vicii.regs[0x1a] = 0;
322
323 vicii.vborder = 1;
324 vicii.set_vborder = 1;
325 vicii.main_border = 1;
326 }
327
vicii_reset_registers(void)328 void vicii_reset_registers(void)
329 {
330 uint16_t i;
331
332 if (!vicii.initialized) {
333 return;
334 }
335
336 for (i = 0; i <= 0x3f; i++) {
337 vicii_store(i, 0);
338 }
339 }
340
341 /* This /should/ put the VIC-II in the same state as after a powerup, if
342 `reset_vicii()' is called afterwards. But FIXME, as we are not really
343 emulating everything correctly here; just $D011. */
vicii_powerup(void)344 void vicii_powerup(void)
345 {
346 memset(vicii.regs, 0, sizeof(vicii.regs));
347
348 vicii.irq_status = 0;
349 vicii.raster_irq_line = 0;
350 vicii.ram_base_phi1 = mem_ram;
351 vicii.ram_base_phi2 = mem_ram;
352
353 vicii.vaddr_mask_phi1 = 0xffff;
354 vicii.vaddr_mask_phi2 = 0xffff;
355 vicii.vaddr_offset_phi1 = 0;
356 vicii.vaddr_offset_phi2 = 0;
357
358 vicii.allow_bad_lines = 0;
359 vicii.sprite_sprite_collisions = vicii.sprite_background_collisions = 0;
360 vicii.clear_collisions = 0x00;
361 vicii.idle_state = 0;
362 vicii.vcbase = 0;
363 vicii.vc = 0;
364 vicii.bad_line = 0;
365 vicii.light_pen.state = 0;
366 vicii.light_pen.x = vicii.light_pen.y = vicii.light_pen.x_extra_bits = vicii.light_pen.triggered = 0;
367 vicii.light_pen.trigger_cycle = CLOCK_MAX;
368 vicii.vbank_phi1 = 0;
369 vicii.vbank_phi2 = 0;
370
371 vicii_reset();
372
373 vicii.ysmooth = 0;
374 }
375
376 /* ---------------------------------------------------------------------*/
377
378 /* This hook is called whenever video bank must be changed. */
vicii_set_vbanks(int vbank_p1,int vbank_p2)379 static inline void vicii_set_vbanks(int vbank_p1, int vbank_p2)
380 {
381 vicii.vbank_phi1 = vbank_p1;
382 vicii.vbank_phi2 = vbank_p2;
383 }
384
385 /* Phi1 and Phi2 accesses */
vicii_set_vbank(int num_vbank)386 void vicii_set_vbank(int num_vbank)
387 {
388 int tmp = num_vbank << 14;
389 vicii_set_vbanks(tmp, tmp);
390 }
391
392 /* Phi1 accesses */
vicii_set_phi1_vbank(int num_vbank)393 void vicii_set_phi1_vbank(int num_vbank)
394 {
395 vicii_set_vbanks(num_vbank << 14, vicii.vbank_phi2);
396 }
397
398 /* Phi2 accesses */
vicii_set_phi2_vbank(int num_vbank)399 void vicii_set_phi2_vbank(int num_vbank)
400 {
401 vicii_set_vbanks(vicii.vbank_phi1, num_vbank << 14);
402 }
403
404 /* ---------------------------------------------------------------------*/
405
406 /* Change the base of RAM seen by the VIC-II. */
vicii_set_ram_bases(uint8_t * base_p1,uint8_t * base_p2)407 static inline void vicii_set_ram_bases(uint8_t *base_p1, uint8_t *base_p2)
408 {
409 vicii.ram_base_phi1 = base_p1;
410 vicii.ram_base_phi2 = base_p2;
411 }
412
vicii_set_ram_base(uint8_t * base)413 void vicii_set_ram_base(uint8_t *base)
414 {
415 vicii_set_ram_bases(base, base);
416 }
417
vicii_set_phi1_ram_base(uint8_t * base)418 void vicii_set_phi1_ram_base(uint8_t *base)
419 {
420 vicii_set_ram_bases(base, vicii.ram_base_phi2);
421 }
422
vicii_set_phi2_ram_base(uint8_t * base)423 void vicii_set_phi2_ram_base(uint8_t *base)
424 {
425 vicii_set_ram_bases(vicii.ram_base_phi1, base);
426 }
427
vicii_update_memory_ptrs_external(void)428 void vicii_update_memory_ptrs_external(void)
429 {
430 }
431
432 /* Redraw the current raster line. This happens after the last cycle
433 of each line. */
vicii_raster_draw_handler(void)434 void vicii_raster_draw_handler(void)
435 {
436 int in_visible_area;
437
438 in_visible_area = (vicii.raster.current_line
439 >= (unsigned int)vicii.first_displayed_line
440 && vicii.raster.current_line
441 <= (unsigned int)vicii.last_displayed_line);
442
443 /* handle wrap if the first few lines are displayed in the visible lower border */
444 if ((unsigned int)vicii.last_displayed_line >= vicii.screen_height) {
445 in_visible_area |= vicii.raster.current_line
446 <= ((unsigned int)vicii.last_displayed_line - vicii.screen_height);
447 }
448
449 raster_line_emulate(&vicii.raster);
450
451 if (vicii.raster.current_line == 0) {
452 /* no vsync here for NTSC */
453 if ((unsigned int)vicii.last_displayed_line < vicii.screen_height) {
454 raster_skip_frame(&vicii.raster,
455 vsync_do_vsync(vicii.raster.canvas,
456 vicii.raster.skip_frame));
457 }
458
459 }
460
461 /* vsync for NTSC */
462 if ((unsigned int)vicii.last_displayed_line >= vicii.screen_height
463 && vicii.raster.current_line == vicii.last_displayed_line - vicii.screen_height + 1) {
464 raster_skip_frame(&vicii.raster,
465 vsync_do_vsync(vicii.raster.canvas,
466 vicii.raster.skip_frame));
467 }
468 }
469
vicii_set_canvas_refresh(int enable)470 void vicii_set_canvas_refresh(int enable)
471 {
472 raster_set_canvas_refresh(&vicii.raster, enable);
473 }
474
vicii_shutdown(void)475 void vicii_shutdown(void)
476 {
477 raster_shutdown(&vicii.raster);
478 }
479
vicii_screenshot(screenshot_t * screenshot)480 void vicii_screenshot(screenshot_t *screenshot)
481 {
482 uint16_t screen_addr; /* Screen start address. */
483 uint8_t *screen_base_phi2; /* Pointer to screen memory. */
484 uint8_t *char_base; /* Pointer to character memory. */
485 uint8_t *bitmap_low_base; /* Pointer to bitmap memory (low part). */
486 uint8_t *bitmap_high_base; /* Pointer to bitmap memory (high part). */
487 int tmp, bitmap_bank;
488
489 screen_addr = vicii.vbank_phi2 + ((vicii.regs[0x18] & 0xf0) << 6);
490
491 screen_addr = (screen_addr & vicii.vaddr_mask_phi2)
492 | vicii.vaddr_offset_phi2;
493
494 tmp = (vicii.regs[0x18] & 0xe) << 10;
495 tmp = (tmp + vicii.vbank_phi1);
496 tmp &= vicii.vaddr_mask_phi1;
497 tmp |= vicii.vaddr_offset_phi1;
498
499 bitmap_bank = tmp & 0xe000;
500 bitmap_low_base = vicii.ram_base_phi1 + bitmap_bank;
501
502 if (export.ultimax_phi2) {
503 if ((screen_addr & 0x3fff) >= 0x3000) {
504 screen_base_phi2 = ultimax_romh_phi2_ptr((uint16_t)(0x1000 + (screen_addr & 0xfff)));
505 } else {
506 screen_base_phi2 = vicii.ram_base_phi2 + screen_addr;
507 }
508 } else {
509 if ((screen_addr & vicii.vaddr_chargen_mask_phi2)
510 != vicii.vaddr_chargen_value_phi2) {
511 screen_base_phi2 = vicii.ram_base_phi2 + screen_addr;
512 } else {
513 screen_base_phi2 = mem_chargen_rom_ptr + (screen_addr & 0xc00);
514 }
515 }
516
517 if (export.ultimax_phi1) {
518 if ((tmp & 0x3fff) >= 0x3000) {
519 char_base = ultimax_romh_phi1_ptr((uint16_t)(0x1000 + (tmp & 0xfff)));
520 } else {
521 char_base = vicii.ram_base_phi1 + tmp;
522 }
523
524 if (((bitmap_bank + 0x1000) & 0x3fff) >= 0x3000) {
525 bitmap_high_base = ultimax_romh_phi1_ptr(0x1000);
526 } else {
527 bitmap_high_base = bitmap_low_base + 0x1000;
528 }
529 } else {
530 if ((tmp & vicii.vaddr_chargen_mask_phi1)
531 != vicii.vaddr_chargen_value_phi1) {
532 char_base = vicii.ram_base_phi1 + tmp;
533 } else {
534 char_base = mem_chargen_rom_ptr + (tmp & 0x0800);
535 }
536
537 if (((bitmap_bank + 0x1000) & vicii.vaddr_chargen_mask_phi1)
538 != vicii.vaddr_chargen_value_phi1) {
539 bitmap_high_base = bitmap_low_base + 0x1000;
540 } else {
541 bitmap_high_base = mem_chargen_rom_ptr;
542 }
543 }
544
545 raster_screenshot(&vicii.raster, screenshot);
546
547 screenshot->chipid = "VICII";
548 screenshot->video_regs = vicii.regs;
549 screenshot->screen_ptr = screen_base_phi2;
550 screenshot->chargen_ptr = char_base;
551 screenshot->bitmap_ptr = NULL;
552 screenshot->bitmap_low_ptr = bitmap_low_base;
553 screenshot->bitmap_high_ptr = bitmap_high_base;
554 screenshot->color_ram_ptr = mem_color_ram_vicii;
555 }
556
vicii_async_refresh(struct canvas_refresh_s * refresh)557 void vicii_async_refresh(struct canvas_refresh_s *refresh)
558 {
559 raster_async_refresh(&vicii.raster, refresh);
560 }
561
562 /* ---------------------------------------------------------------------*/
563
fetch_phi1_type(int addr)564 static const char *fetch_phi1_type(int addr)
565 {
566 addr = (addr & vicii.vaddr_mask_phi1) | vicii.vaddr_offset_phi1;
567
568 if (export.ultimax_phi1) {
569 if ((addr & 0x3fff) >= 0x3000) {
570 return "Cart";
571 } else {
572 return "RAM";
573 }
574 } else {
575 if ((addr & vicii.vaddr_chargen_mask_phi1) == vicii.vaddr_chargen_value_phi1) {
576 return "CharROM";
577 } else {
578 return "RAM";
579 }
580 }
581 }
582
583
vicii_dump(void)584 int vicii_dump(void)
585 {
586 static const char *mode_name[] = {
587 "Standard Text",
588 "Multicolor Text",
589 "Hires Bitmap",
590 "Multicolor Bitmap",
591 "Extended Text",
592 "Illegal Text",
593 "Invalid Bitmap 1",
594 "Invalid Bitmap 2"
595 };
596
597 int video_mode, m_mcm, m_bmm, m_ecm, v_bank, v_vram;
598 int i, bits, bits2;
599
600 video_mode = ((vicii.regs[0x11] & 0x60) | (vicii.regs[0x16] & 0x10)) >> 4;
601
602 m_ecm = (video_mode & 4) >> 2; /* 0 standard, 1 extended */
603 m_bmm = (video_mode & 2) >> 1; /* 0 text, 1 bitmap */
604 m_mcm = video_mode & 1; /* 0 hires, 1 multi */
605
606 v_bank = vicii.vbank_phi1;
607
608 mon_out("Raster cycle/line: %d/%d IRQ: %d\n", vicii.raster_cycle, vicii.raster_line, vicii.raster_irq_line);
609 mon_out("Mode: %s (ECM/BMM/MCM=%d/%d/%d)\n", mode_name[video_mode], m_ecm, m_bmm, m_mcm);
610 mon_out("Colors: Border: %x BG: %x ", vicii.regs[0x20], vicii.regs[0x21]);
611 if (m_ecm) {
612 mon_out("BG1: %x BG2: %x BG3: %x\n", vicii.regs[0x22], vicii.regs[0x23], vicii.regs[0x24]);
613 } else if (m_mcm && !m_bmm) {
614 mon_out("MC1: %x MC2: %x\n", vicii.regs[0x22], vicii.regs[0x23]);
615 } else {
616 mon_out("\n");
617 }
618
619 mon_out("Scroll X/Y: %d/%d, RC %d, Idle: %d, ", vicii.regs[0x16] & 0x07, vicii.regs[0x11] & 0x07, vicii.rc, vicii.idle_state);
620 mon_out("%dx%d\n", 39 + ((vicii.regs[0x16] >> 3) & 1), 24 + ((vicii.regs[0x11] >> 3) & 1));
621
622 mon_out("VC $%03x, VCBASE $%03x, VMLI %2d, Phi1 $%02x\n", vicii.vc, vicii.vcbase, vicii.vmli, vicii.last_read_phi1);
623
624 v_vram = ((vicii.regs[0x18] >> 4) * 0x0400) + vicii.vbank_phi2;
625 mon_out("Video $%04x, ", v_vram);
626 if (m_bmm) {
627 i = ((vicii.regs[0x18] >> 3) & 1) * 0x2000 + v_bank;
628 mon_out("Bitmap $%04x (%s)\n", i, fetch_phi1_type(i));
629 } else {
630 i = (((vicii.regs[0x18] >> 1) & 0x7) * 0x800) + v_bank;
631 mon_out("Charset $%04x (%s)\n", i, fetch_phi1_type(i));
632 }
633
634 mon_out("\nSprites: S.0 S.1 S.2 S.3 S.4 S.5 S.6 S.7");
635 mon_out("\nEnabled:");
636 bits = vicii.regs[0x15];
637 for (i = 0; i < 8; i++) {
638 mon_out("%4s", (bits & 1) ? "yes" : "no");
639 bits >>= 1;
640 }
641
642 mon_out("\nDMA/dis:");
643 bits = vicii.sprite_dma;
644 bits2 = vicii.sprite_display_bits;
645 for (i = 0; i < 8; i++) {
646 mon_out(" %c/%c", (bits & 1) ? 'D' : ' ', (bits2 & 1) ? 'd' : ' ');
647 bits >>= 1;
648 bits2 >>= 1;
649 }
650
651 mon_out("\nPointer:");
652 for (i = 0; i < 8; i++) {
653 mon_out(" $%02x", vicii.sprite[i].pointer);
654 }
655
656 mon_out("\nMC: ");
657 for (i = 0; i < 8; i++) {
658 mon_out(" $%02x", vicii.sprite[i].mc);
659 }
660
661 mon_out("\nMCBASE: ");
662 for (i = 0; i < 8; i++) {
663 mon_out(" $%02x", vicii.sprite[i].mcbase);
664 }
665
666 mon_out("\nX-Pos: ");
667 for (i = 0; i < 8; i++) {
668 mon_out("$%03x", vicii.sprite[i].x);
669 }
670 mon_out("\nY-Pos: ");
671 for (i = 0; i < 8; i++) {
672 mon_out("%4d", vicii.regs[1 + (i << 1)]);
673 }
674 mon_out("\nX/Y-Exp:");
675 bits = vicii.regs[0x1d];
676 bits2 = vicii.regs[0x17];
677 for (i = 0; i < 8; i++) {
678 mon_out(" %c/%c", (bits & 1) ? 'X' : ' ', (bits2 & 1) ? (vicii.sprite[i].exp_flop ? 'Y' : 'y') : ' ');
679 bits >>= 1;
680 bits2 >>= 1;
681 }
682 mon_out("\nPri./MC:");
683 bits = vicii.regs[0x1b];
684 bits = vicii.regs[0x1c];
685 for (i = 0; i < 8; i++) {
686 mon_out(" %c/%c", (bits & 1) ? 'b' : 's', (bits2 & 1) ? '*' : ' ');
687 bits >>= 1;
688 }
689 mon_out("\nColor: ");
690 for (i = 0; i < 8; i++) {
691 mon_out(" %x", vicii.regs[i + 0x27]);
692 }
693 if (vicii.regs[0x1c]) {
694 mon_out("\nMulti Color 1: %x Multi Color 2: %x", vicii.regs[0x25], vicii.regs[0x26]);
695 }
696 mon_out("\n");
697
698 return 0;
699 }
700