VirtualC64 v5.0 beta
Commodore 64 Emulator
Loading...
Searching...
No Matches
VICII.h
1// -----------------------------------------------------------------------------
2// This file is part of VirtualC64
3//
4// Copyright (C) Dirk W. Hoffmann. www.dirkwhoffmann.de
5// This FILE is dual-licensed. You are free to choose between:
6//
7// - The GNU General Public License v3 (or any later version)
8// - The Mozilla Public License v2
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR MPL-2.0
11// -----------------------------------------------------------------------------
12
13#pragma once
14
15#include "VICIITypes.h"
16#include "SubComponent.h"
17#include "Colors.h"
18#include "Constants.h"
19#include "DmaDebugger.h"
20#include "MemoryTypes.h"
21#include "MonitorTypes.h"
22#include "TimeDelayed.h"
23
24namespace vc64 {
25
26struct VICIIRegisters : Serializable
27{
28 // Registers
29 u16 sprX[8]; // D000, D002, ..., D00E, upper bits from D010
30 u8 sprY[8]; // D001, D003, ..., D00F
31 u8 ctrl1; // D011
32 u8 sprEnable; // D015
33 u8 ctrl2; // D016
34 u8 sprExpandY; // D017
35 u8 sprPriority; // D01B
36 u8 sprMC; // D01C
37 u8 sprExpandX; // D01D
38 u8 colors[15]; // D020 - D02E
39
40 // Derived values
41 u8 xscroll;
42 DisplayMode mode;
43
44
45 template <class W>
46 void serialize(W& worker)
47 {
48 worker
49
50 << sprX
51 << sprY
52 << ctrl1
53 << sprEnable
54 << ctrl2
55 << sprExpandY
56 << sprPriority
57 << sprMC
58 << sprExpandX
59 << colors
60 << xscroll
61 << mode;
62
63 } SERIALIZERS(serialize);
64};
65
66struct SpriteSR : Serializable
67{
68 // Shift register data (24 bit)
69 u32 data;
70
71 // The shift register data is read in three chunks
72 u8 chunk1, chunk2, chunk3;
73
74 /* Multi-color synchronization flipflop
75 * Whenever the shift register is loaded, the synchronization flipflop
76 * is also set. It is toggled with each pixel and used to synchronize
77 * the synthesis of multi-color pixels.
78 */
79 bool mcFlop;
80
81 // X expansion synchronization flipflop
82 bool expFlop;
83
84 /* Color bits of the currently processed pixel
85 * In single-color mode, these bits are updated every cycle. In
86 * multi-color mode, these bits are updated every second cycle
87 * (synchronized with mcFlop).
88 */
89 u8 colBits;
90
91 template <class W>
92 void serialize(W& worker)
93 {
94 worker
95
96 << data
97 << chunk1
98 << chunk2
99 << chunk3
100 << mcFlop
101 << expFlop
102 << colBits;
103
104 } SERIALIZERS(serialize);
105};
106
107class VICII final : public SubComponent, public Inspectable<VICIIInfo, VICIIStats> {
108
109 friend class C64Memory;
110 friend class DmaDebugger;
111 friend class VideoPort;
112
113 // REMOVE ASAP
114 friend class Heatmap;
115
116 Descriptions descriptions = {{
117
118 .name = "VIC",
119 .description = "Video Interface Controller"
120 }};
121
122 static constexpr VICIITraits traits[6] = {
123 {
124 // VICII_PAL_6569_R1
125 .pal = true,
126 .frequency = PAL::CLOCK_FREQUENCY,
127 .fps = PAL::CLOCK_FREQUENCY / (312.0 * 63.0),
128 .linesPerFrame = 312,
129 .cyclesPerLine = 63,
130 .cyclesPerFrame = 312 * 63,
131 .visibleLines = 284,
132 .grayCodeBug = false,
133 .delayedLpIrqs = true
134 },
135 {
136 // VICII_PAL_6569_R3
137 .pal = true,
138 .frequency = PAL::CLOCK_FREQUENCY,
139 .fps = PAL::CLOCK_FREQUENCY / (312.0 * 63.0),
140 .linesPerFrame = 312,
141 .cyclesPerLine = 63,
142 .cyclesPerFrame = 312 * 63,
143 .visibleLines = 284,
144 .grayCodeBug = false,
145 .delayedLpIrqs = false
146 },
147 {
148 // VICII_PAL_8565
149 .pal = true,
150 .frequency = PAL::CLOCK_FREQUENCY,
151 .fps = PAL::CLOCK_FREQUENCY / (312.0 * 63.0),
152 .linesPerFrame = 312,
153 .cyclesPerLine = 63,
154 .cyclesPerFrame = 312 * 63,
155 .visibleLines = 284,
156 .grayCodeBug = true,
157 .delayedLpIrqs = false
158 },
159 {
160 // VICII_NTSC_6567_R56A
161 .pal = false,
162 .frequency = NTSC::CLOCK_FREQUENCY,
163 .fps = NTSC::CLOCK_FREQUENCY / (262.0 * 64.0),
164 .linesPerFrame = 262,
165 .cyclesPerLine = 64,
166 .cyclesPerFrame = 262 * 64,
167 .visibleLines = 234,
168 .grayCodeBug = false,
169 .delayedLpIrqs = true
170 },
171 {
172 // VICII_NTSC_6567
173 .pal = false,
174 .frequency = NTSC::CLOCK_FREQUENCY,
175 .fps = NTSC::CLOCK_FREQUENCY / (263.0 * 65.0),
176 .linesPerFrame = 263,
177 .cyclesPerLine = 65,
178 .cyclesPerFrame = 263 * 65,
179 .visibleLines = 235,
180 .grayCodeBug = false,
181 .delayedLpIrqs = false
182 },
183 {
184 // VICII_NTSC_8562
185 .pal = false,
186 .frequency = NTSC::CLOCK_FREQUENCY,
187 .fps = NTSC::CLOCK_FREQUENCY / (263.0 * 65.0),
188 .linesPerFrame = 263,
189 .cyclesPerLine = 65,
190 .cyclesPerFrame = 263 * 65,
191 .visibleLines = 235,
192 .grayCodeBug = true,
193 .delayedLpIrqs = false
194 }
195 };
196
197 ConfigOptions options = {
198
206 };
207
208 // Current configuration
209 VICIIConfig config = { };
210
211 // Result of the latest inspection
212 mutable SpriteInfo spriteInfo[8] = { };
213
214 // Chip properties (derived from config.revision)
215 bool isPAL;
216 bool isNTSC;
217 bool is856x;
218 bool is656x;
219
220public:
221
222 // Sub components
223 DmaDebugger dmaDebugger;
224
225 /* The VICII function table. Each entry in this table is a pointer to a
226 * VICII method executed in a certain scanline cycle:
227 *
228 * functable[model][flags][cycle]
229 *
230 * model: VICII revision
231 *
232 * flags: One or more of the following:
233 *
234 * CYCLE_PAL : Emulates a PAL cycle, NTSC otherwise
235 * CYCLE_DMA : Runs the DMA debugger code for the specific cycle
236 * CYLCE_HEADLESS : Skips all pixel-drawing related code
237 *
238 * cycle: 1 .. 65 (cycle 0 is a stub and never called)
239 *
240 * CYCLE_DMA and CYCLE_HEADLESS must be be set simultaneously as this
241 * combination does not make sense.
242 */
243 typedef void (VICII::*ViciiFunc)(void);
244 ViciiFunc functable[6][8][66] = {};
245
246 // Function pointers currently in use
247 ViciiFunc vicfunc[66] = {};
248
249
250 //
251 // I/O space (CPU accessible)
252 //
253
254private:
255
256 /* Piped I/O register state. When an I/O register is written to, the
257 * corresponding value in variable current is changed and a flag is set in
258 * variable delay. Function processDelayedActions() reads the flag and, if
259 * set to true, updates the delayed values.
260 */
261 struct {
262 VICIIRegisters current;
263 VICIIRegisters delayed;
264 } reg;
265
266 // Raster interrupt line ($D011:8 + $D012)
267 u16 rasterIrqLine;
268
269 // Latched lightpen coordinates ($D013 and $D014)
270 u8 latchedLPX;
271 u8 latchedLPY;
272
273 // Memory address register ($D018)
274 u8 memSelect;
275
276 // Interrupt Request and Mask Register ($D019 and $D01A)
277 u8 irr;
278 u8 imr;
279
280
281 //
282 // Chip internals
283 //
284
285 // IRQ <---------------------------------+
286 // (1) |
287 // +---------------+ +-----------------+
288 // |Refresh counter| | Interrupt logic |<----------------------+
289 // +---------------+ +-----------------+ |
290 // +-+ | ^ |
291 // A |M| v (2),(3) | (4),(5) |
292 // d |e| +-+ +--------------+ +-------+ |
293 // d |m| |A| |Raster counter|->| VC/RC | |
294 // r |o| |d| +->| X/Y | +-------+ |
295 // . <==>|r| |d| | +--------------+ | |
296 // + |y| |r| | | | | | (6),(7) |
297 // d | | |.|<--------+----------------+ +------------------------+ |
298 // a |i| |g|===========================>|40×12 bit video matrix-/| |
299 // t |n|<=>|e| | | | | color line | |
300 // a |t| |n| | | | +------------------------+ |
301 // |e| |e| | | | (8) || |
302 // |r| |r| | | | +----------------+ || |
303 // BA <--|f| |a|============>|8×24 bit sprite | || |
304 // |a| |t|<----+ | | | data buffers | || |
305 // AEC <--|c| |o| | | v | +----------------+ || |
306 // |e| |r| | +-----+ | || || |
307 // +-+ +-+ | |MC0-7| | (10) \/ (11) \/ |
308 // | +-----+ | +--------------+ +--------------+ |
309 // | (9) | | Sprite data | |Graphics data | |
310 // +---------------+ | | sequencer | | sequencer | |
311 // RAS <--| | | +--------------+ +--------------+ |
312 // CAS <--|Clock generator| | | | |
313 // ø0 <--| | | v v |
314 // +---------------+ | +-----------------------+ |
315 // ^ | | MUX | |
316 // | | | Sprite priorities and |-----------+
317 // øIN -----------+ | | collision detection |
318 // | +-----------------------+ (12)
319 // VC: Video Matrix Counter | |
320 // (14) | (13) v
321 // RC: Row Counter | +-------------+
322 // (15) +----------->| Border unit |
323 // MC: MOB Data Counter | +-------------+
324 // (16) | |
325 // v v
326 // +----------------+ +----------------+
327 // |Sync generation | |Color generation|<------- øCOLOR
328 // +----------------+ +----------------+
329 // | |
330 // v v
331 // Video output
332 // (S/LUM and COLOR) [C.B.]
333
334
335 /* Refresh counter (1): "The VICII does five read accesses in every raster
336 * line for the refresh of the dynamic RAM. An 8 bit refresh counter (REF)
337 * is used to generate 256 DRAM row addresses. The counter is reset to $ff
338 * in raster line 0 and decremented by 1 after each refresh access." [C.B.]
339 * See also: rAccess()
340 */
341 u8 refreshCounter;
342
343 /* Raster counter X (2): Defines the sprite coordinate system.
344 */
345 u16 xCounter;
346
347 /* Y raster counter (3): The scanline counter is usually incremented in
348 * cycle 1. The only exception is the overflow condition which is handled
349 * in cycle 2.
350 */
351 u32 yCounter;
352
353 /* Video counter (14): A 10 bit counter that can be loaded with the value
354 * from vcBase.
355 */
356 u16 vc;
357
358 /* Video counter base: A 10 bit data register that can be loaded with the
359 * value from vc.
360 */
361 u16 vcBase;
362
363 /* Row counter (15): A 3 bit counter with reset input.
364 */
365 u8 rc;
366
367 /* Video matrix (6): Every 8th scanline, the VICII chips performs a
368 * c-access and fills this array with character information.
369 */
370 u8 videoMatrix[40];
371
372 /* Color line (7): Every 8th scanline, the VICII chips performs a
373 * c-access and fills the array with color information.
374 */
375 u8 colorLine[40];
376
377 /* Video matrix line index: "Besides this, there is a 6 bit counter with
378 * reset input that keeps track of the position within the internal 40×12
379 * bit video matrix/color line where read character pointers are stored
380 * resp. read again. I will call this 'VMLI' (video matrix line index)
381 * here." [C.B.]
382 */
383 u8 vmli;
384
385
386 /* Graphics data sequencer (10): An 8 bit shift register to synthesize
387 * canvas pixels.
388 */
389 struct {
390
391 // Shift register data
392 u8 data;
393
394 /* Indicates whether the shift register can load data. If true, the
395 * register is loaded when the current x scroll offset matches the
396 * current pixel number.
397 */
398 bool canLoad;
399
400 /* Multi-color synchronization flipflop. Whenever the shift register is
401 * loaded, the synchronization flipflop is also set. It is toggled with
402 * each pixel and used to synchronize the synthesis of multi-color
403 * pixels.
404 */
405 bool mcFlop;
406
407 /* Latched character info. Whenever the shift register is loaded, the
408 * current character value (which was once read during a gAccess) is
409 * latched. This value is used until the shift register loads again.
410 */
411 u8 latchedChr;
412
413 /* Latched color info. Whenever the shift register is loaded, the
414 * current color value (which was once read during a gAccess) is
415 * latched. This value is used until the shift register loads again.
416 */
417 u8 latchedCol;
418
419 /* Color bits. Every second pixel (as synchronized with mcFlop), the
420 * multi-color bits are remembered.
421 */
422 u8 colorbits;
423
424 } sr;
425
426 /* Sprite data sequencer (11): The VICII chip has a 24 bit (3 byte) shift
427 * register for each sprite. It stores the sprite for one scanline. If a
428 * sprite is a display candidate in the current scanline, its shift
429 * register is activated when the raster X coordinate matches the sprites
430 * X coordinate. The comparison is done in method drawSprite(). Once a
431 * shift register is activated, it remains activated until the beginning of
432 * the next scanline. However, after an activated shift register has
433 * dumped out its 24 pixels, it can't draw anything else than transparent
434 * pixels (which is the same as not to draw anything). An exception is
435 * during DMA cycles. When a shift register is activated during such a
436 * cycle, it freezes a short period of time in which it repeats the
437 * previous drawn pixel.
438 */
439 SpriteSR spriteSr[8];
440
441 /* Indicates for each sprite if the shift register is active. Once the
442 * shift register is started, it runs as long it contains at least one '1'
443 * bit (data != 0).
444 */
445 u8 spriteSrActive;
446
447 // Sprite-sprite collision register (12)
448 u8 spriteSpriteCollision;
449
450 // Sprite-background collision register (12)
451 u8 spriteBackgroundColllision;
452
453
454 //
455 // Border flipflops
456 //
457
458 /* Piped frame flipflops state (13): When a flipflop toggles, the value in
459 * variable 'current' is changed and a flag is set in variable 'delay'.
460 * Function processDelayedActions() reads the flag and if set to true,
461 * updates the delayed values with the current ones.
462 */
463 struct {
464 FrameFlipflops current;
465 FrameFlipflops delayed;
466 } flipflops;
467
468 /* Vertical frame flipflop set condition. Indicates whether the vertical
469 * frame flipflop needs to be set in the current scanline.
470 */
471 bool verticalFrameFFsetCond;
472
473 /* First coordinate where the main frame flipflop is checked. Either 24 or
474 * 31, dependend on the CSEL bit.
475 */
476 u16 leftComparisonVal;
477
478 /* Second coordinate where the main frame flipflop is checked. Either 344
479 * or 335, dependend on the CSEL bit.
480 */
481 u16 rightComparisonVal;
482
483 /* First coordinate where the vertical frame flipflop is checked. Either 51
484 * or 55, dependend on the RSEL bit.
485 */
486 u16 upperComparisonVal;
487
488 /* Second coordinate where the vertical frame flipflop is checked. Either
489 * 251 or 247, dependend on the RSEL bit.
490 */
491 u16 lowerComparisonVal;
492
493
494 //
495 // Raster interrupt logic
496 //
497
498 /* Indicates whether the current raster line matches the IRQ line. A
499 * positive edge on this value triggers a raster interrupt.
500 */
501 bool lineMatchesIrqLine;
502
503
504 //
505 // Housekeeping information
506 //
507
508 /* Indicates wether we are in a visible display column or not. The visible
509 * columns comprise canvas columns and border columns. The first visible
510 * column is drawn in cycle 14 (first left border column) and the last in
511 * cycle 61 (fourth right border column).
512 */
513 bool isVisibleColumn;
514
515 // True if the current scanline belongs to the VBLANK area
516 bool vblank;
517
518 // Indicates if the current scanline is a DMA line (bad line)
519 bool badLine;
520
521 /* True, if DMA lines can occurr within the current frame. Bad lines can
522 * occur only if the DEN bit was set during an arbitary cycle in scanline
523 * 30. The DEN bit is located in control register 1 (0x11).
524 */
525 bool DENwasSetInLine30;
526
527 /* Current display State
528 *
529 * "The text/bitmap display logic in the VICII is in one of two states at
530 * any time: The idle state and the display state.
531 *
532 * - In display state, c- and g-accesses take place, the addresses and
533 * interpretation of the data depend on the selected display mode.
534 *
535 * - In idle state, only g-accesses occur. The VICII is either in idle or
536 * display state" [C.B.]
537 */
538 bool displayState;
539
540
541 //
542 // Sprites
543 //
544
545private:
546
547 // MOB data counter (16)
548 u8 mc[8];
549
550 // MCBASE register
551 u8 mcbase[8];
552
553 // Sprite pointer fetched during a pAccess
554 u16 spritePtr[8];
555
556 // Flags the first DMA access for each sprite
557 u8 isFirstDMAcycle;
558
559 // Flags the second or third DMA access for each sprite
560 u8 isSecondDMAcycle;
561
562 // Determines if a sprite needs to be drawn in the current scanline
563 u8 spriteDisplay;
564
565 // Value of spriteDisplay, delayed by one cycle
566 u8 spriteDisplayDelayed;
567
568 // Sprite DMA on off register
569 u8 spriteDmaOnOff;
570
571 // Expansion flipflop (used to handle Y sprite stretching)
572 u8 expansionFF;
573
574 /* Remembers which bits the CPU has cleared in the expansion Y register
575 * (D017). This value is set in pokeIO and cycle 15 and read in cycle 16
576 */
577 u8 cleared_bits_in_d017;
578
579 // Collision bits
580 u8 collision[8];
581
582
583 //
584 // Lightpen
585 //
586
587 /* Current value of the LP pin. A negative transition on this pin triggers
588 * a lightpen interrupt.
589 */
590 bool lpLine;
591
592 /* Indicates whether the lightpen has triggered. This variable indicates
593 * whether a lightpen interrupt has occurred within the current frame. The
594 * variable is needed, because a lightpen interrupt can only occur once per
595 * frame.
596 */
597 bool lpIrqHasOccurred;
598
599
600 //
601 // CPU control and memory access
602 //
603
604private:
605
606 /* Memory source lookup table. If VICII is not running in Ultimax mode, it
607 * has access to RAM and the character Rom. In ultimax mode, VICII has
608 * access to ROMH and some portions of RAM.
609 */
610 MemoryType memSrc[16];
611
612 /* Indicates whether VICII is running in ultimax mode. Ultimax mode can be
613 * enabled by external cartridges by pulling the game line low and keeping
614 * the exrom line high. In ultimax mode, VICII has access to ROMH and some
615 * portions of RAM.
616 */
617 bool ultimax;
618
619 /* Value on the data bus during the latest phi1 access. Only VICII performs
620 * a memory access during phi1.
621 */
622 u8 dataBusPhi1;
623
624 /* Value on the data bus during the latest phi2 access. VICII or the CPU
625 * can perform a memory access during phi2. If none of them does, 0xFF will
626 * be on the bus.
627 */
628 u8 dataBusPhi2;
629
630 /* Address bus. Whenever VICII performs a memory read, the generated memory
631 * address is stored in this variable.
632 */
633 u16 addrBus;
634
635 /* Current value of the BA line. Remember: Each CPU cycle is split into two
636 * phases:
637 *
638 * - phi1 (First phase, LOW): VICII gets access to the bus
639 * - phi2 (Second phase, HIGH): CPU gets access to the bus
640 *
641 * In rare cases, VICII needs access in the HIGH phase, too. To block the
642 * CPU, the BA line is pulled down. Note that BA can be pulled down by
643 * multiple sources (wired AND) and this variable indicates which sources
644 * are holding the line low.
645 */
646 TimeDelayed <u16,3> baLine = TimeDelayed <u16,3> ();
647
648 /* Start address of the currently selected memory bank. There are four
649 * banks in total since the VICII chip can only 'see' 16 KB of memory at
650 * the same time. Two bank select bits in the CIA I/O space determine which
651 * quarter of memory is currently seen.
652 *
653 * +-------+------+-------+----------+-------------------------+
654 * | VALUE | BITS | BANK | STARTING | VIC-II CHIP RANGE |
655 * | OF A | | | LOCATION | |
656 * +-------+------+-------+----------+-------------------------+
657 * | 0 | 00 | 3 | 49152 | ($C000-$FFFF) |
658 * | 1 | 01 | 2 | 32768 | ($8000-$BFFF) |
659 * | 2 | 10 | 1 | 16384 | ($4000-$7FFF) |
660 * | 3 | 11 | 0 | 0 | ($0000-$3FFF) (DEFAULT) |
661 * +-------+------+-------+----------+-------------------------+
662 */
663 u16 bankAddr;
664
665 // Result of the lastest g-access
666 TimeDelayed <u32,2> gAccessResult = TimeDelayed <u32,2> ();
667
668
669 //
670 // Pipeline
671 //
672
673private:
674
675 /* Event pipeline. If a time delayed event needs to be performed, a flag is
676 * set inside this variable and executed at the beginning of the next cycle.
677 * See processDelayedActions()
678 */
679 u64 delay;
680
681
682 //
683 // Screen buffers and colors
684 //
685
686private:
687
688 // C64 colors in RGBA format (updated in updatePalette())
689 u32 rgbaTable[16];
690
691 /* Texture buffers. VICII outputs the generated texture into these buffers.
692 * At any time, one buffer is the working buffer and the other one is the
693 * stable buffer. While VICII always writes into the working buffer, the
694 * GUI accesses the stable buffer at a constant frame rate and copies it
695 * into the texture RAM of the graphics card.
696 *
697 * The emuTexture buffers contain the emulator texture. It is the texture
698 * that is usually drawn by the GUI. The dmaTexture buffers contain the
699 * texture generated by the DMA debugger. If DMA debugging is enabled, this
700 * texture is superimposed on the emulator texture.
701 */
702 u32 *emuTexture1 = new u32[Texture::height * Texture::width];
703 u32 *emuTexture2 = new u32[Texture::height * Texture::width];
704 u32 *dmaTexture1 = new u32[Texture::height * Texture::width];
705 u32 *dmaTexture2 = new u32[Texture::height * Texture::width];
706
707 /* Pointer to the current working texture. This variable points either to
708 * the first or the second texture buffer. After a frame has been finished,
709 * the pointer is redirected to the other buffer.
710 */
711 u32 *emuTexture;
712 u32 *dmaTexture;
713
714 /* Pointer to the beginning of the current scanline inside the current
715 * working textures. These pointers are used by all rendering methods to
716 * write pixels. It always points to the beginning of a scanline, either
717 * the first or the second texture buffer. They are reset at the beginning
718 * of each frame and incremented at the beginning of each scanline.
719 */
720 u32 *emuTexturePtr;
721 u32 *dmaTexturePtr;
722
723 /* VICII utilizes a depth buffer to determine pixel priority. The render
724 * routines only write a color value, if it is closer to the view point.
725 * The depth of the closest pixel is kept in this buffer. The lower the
726 * value, the closer it is to the viewer.
727 * The depth values have been chosen in a way that preserves the source
728 * of the drawn pixel (border pixel, sprite pixel, etc.).
729 */
730 u8 zBuffer[Texture::width];
731
732 /* Offset into to pixelBuffer. This variable points to the first pixel of
733 * the currently drawn 8 pixel chunk.
734 */
735 short bufferoffset;
736
737
738 //
739 // Debugging
740 //
741
742 // Lookup table for DMA debugging colors
743 u32 debugColor[6][4];
744
745public:
746
747 // Filename used by dumpTexture()
748 string dumpTexturePath = "texture";
749
750 // Pixel area used by dumpTexture()
751 isize x1 = 104;
752 isize y1 = 16;
753 isize x2 = 488;
754 isize y2 = 290;
755
756
757 //
758 // Methods
759 //
760
761public:
762
763 VICII(C64 &ref);
764
765 VICII& operator= (const VICII& other) {
766
767 CLONE(dmaDebugger)
768
769 CLONE(reg)
770 CLONE(rasterIrqLine)
771 CLONE(latchedLPX)
772 CLONE(latchedLPY)
773 CLONE(memSelect)
774 CLONE(irr)
775 CLONE(imr)
776 CLONE(refreshCounter)
777 CLONE(xCounter)
778 CLONE(yCounter)
779 CLONE(vc)
780 CLONE(vcBase)
781 CLONE(rc)
782 CLONE_ARRAY(videoMatrix)
783 CLONE_ARRAY(colorLine)
784 CLONE(vmli)
785 CLONE(sr)
786 CLONE_ARRAY(spriteSr)
787 CLONE(spriteSrActive)
788 CLONE(spriteSpriteCollision)
789 CLONE(spriteBackgroundColllision)
790 CLONE(flipflops)
791 CLONE(verticalFrameFFsetCond)
792 CLONE(leftComparisonVal)
793 CLONE(rightComparisonVal)
794 CLONE(upperComparisonVal)
795 CLONE(lowerComparisonVal)
796 CLONE(lineMatchesIrqLine)
797 CLONE(isVisibleColumn)
798 CLONE(vblank)
799 CLONE(badLine)
800 CLONE(DENwasSetInLine30)
801 CLONE(displayState)
802 CLONE_ARRAY(mc)
803 CLONE_ARRAY(mcbase)
804 CLONE_ARRAY(spritePtr)
805 CLONE(isFirstDMAcycle)
806 CLONE(isSecondDMAcycle)
807 CLONE(spriteDisplay)
808 CLONE(spriteDisplayDelayed)
809 CLONE(spriteDmaOnOff)
810 CLONE(expansionFF)
811 CLONE(cleared_bits_in_d017)
812 CLONE_ARRAY(collision)
813 CLONE(lpLine)
814 CLONE(lpIrqHasOccurred)
815 CLONE_ARRAY(memSrc)
816 CLONE(ultimax)
817 CLONE(dataBusPhi1)
818 CLONE(dataBusPhi2)
819 CLONE(addrBus)
820 CLONE(baLine)
821 CLONE(bankAddr)
822 CLONE(gAccessResult)
823 CLONE(delay)
824
825 CLONE_ARRAY(rgbaTable)
826
827 CLONE(bufferoffset)
828
829 CLONE_ARRAY(memSrc)
830 CLONE(isPAL)
831 CLONE(isNTSC)
832 CLONE(is856x)
833 CLONE(is656x)
834
835 CLONE(config)
836
837 updateVicFunctionTable();
838 return *this;
839 }
840
841
842 //
843 // Methods from Serializable
844 //
845
846public:
847
848 template <class T>
849 void serialize(T& worker)
850 {
851 worker
852
853 << dmaDebugger
854
855 << reg.current
856 << reg.delayed
857 << rasterIrqLine
858 << latchedLPX
859 << latchedLPY
860 << memSelect
861 << irr
862 << imr
863 << refreshCounter
864 << xCounter
865 << yCounter
866 << vc
867 << vcBase
868 << rc
869 << videoMatrix
870 << colorLine
871 << vmli
872 << sr.data
873 << sr.canLoad
874 << sr.mcFlop
875 << sr.latchedChr
876 << sr.latchedCol
877 << sr.colorbits
878 << spriteSr
879 << spriteSrActive
880 << spriteSpriteCollision
881 << spriteBackgroundColllision
882 << flipflops.current.vertical
883 << flipflops.current.main
884 << flipflops.delayed.vertical
885 << flipflops.delayed.main
886 << verticalFrameFFsetCond
887 << leftComparisonVal
888 << rightComparisonVal
889 << upperComparisonVal
890 << lowerComparisonVal
891 << lineMatchesIrqLine
892 << isVisibleColumn
893 << vblank
894 << badLine
895 << DENwasSetInLine30
896 << displayState
897 << mc
898 << mcbase
899 << spritePtr
900 << isFirstDMAcycle
901 << isSecondDMAcycle
902 << spriteDisplay
903 << spriteDisplayDelayed
904 << spriteDmaOnOff
905 << expansionFF
906 << cleared_bits_in_d017
907 << collision
908 << lpLine
909 << lpIrqHasOccurred
910 << memSrc
911 << ultimax
912 << dataBusPhi1
913 << dataBusPhi2
914 << addrBus
915 << baLine
916 << bankAddr
917 << gAccessResult
918 << delay
919 << bufferoffset;
920
921 if (isResetter(worker)) return;
922
923 worker
924
925 << memSrc
926 << isPAL
927 << isNTSC
928 << is856x
929 << is656x
930
931 << config.revision
932 << config.awaiting
933 << config.powerSave
934 << config.grayDotBug
935 << config.glueLogic;
936
937 } SERIALIZERS(serialize);
938
939
940 //
941 // Methods from CoreComponent
942 //
943
944public:
945
946 const Descriptions &getDescriptions() const override { return descriptions; }
947
948private:
949
950 void _dump(Category category, std::ostream& os) const override;
951 void _initialize() override;
952 void _reset(bool hard) override;
953 void _trackOn() override;
954 void _trackOff() override;
955
956
957 //
958 // Methods from Inspectable
959 //
960
961private:
962
963 void cacheInfo(VICIIInfo &result) const override;
964 void cacheStats(VICIIStats &result) const override;
965 void clearStats() override;
966
967public:
968
969 SpriteInfo getSpriteInfo(isize nr);
970
971
972 //
973 // Methods from Configurable
974 //
975
976public:
977
978 const VICIIConfig &getConfig() const { return config; }
979 const ConfigOptions &getOptions() const override { return options; }
980 i64 getOption(Option opt) const override;
981 void checkOption(Option opt, i64 value) override;
982 void setOption(Option opt, i64 value) override;
983
984 bool dmaDebug() const { return dmaDebugger.config.dmaDebug; }
985
986private:
987
988 void updateRevision();
989 void setRevision(VICIIRevision revision);
990
991
992 //
993 // Initializing
994 //
995
996private:
997
998 void resetEmuTexture(isize nr);
999 void resetEmuTextures() { resetEmuTexture(1); resetEmuTexture(2); }
1000 void resetDmaTexture(isize nr);
1001 void resetDmaTextures() { resetDmaTexture(1); resetDmaTexture(2); }
1002 void resetTexture(u32 *p);
1003
1004 void initFuncTable(VICIIRevision revision);
1005 void initFuncTable(VICIIRevision revision, u16 flags);
1006 ViciiFunc getViciiFunc(u16 flags, isize cycle);
1007 template <u16 flags> ViciiFunc getViciiFunc(isize cycle);
1008
1009public:
1010
1011 void updateVicFunctionTable();
1012
1013
1014 //
1015 // Deriving chip properties
1016 //
1017
1018public:
1019
1020 // Returns properties about the currently selected VICII revision
1021 const VICIITraits &getTraits() const { return traits[config.revision]; }
1022
1023 // Returns true if a PAL or an NTSC chip is plugged in
1024 bool pal() const { return isPAL; }
1025 bool ntsc() const { return isNTSC; }
1026
1027 // Returns true if light pen interrupts are triggered with a delay
1028 static bool delayedLightPenIrqs(VICIIRevision rev);
1029 bool delayedLightPenIrqs() { return delayedLightPenIrqs(config.revision); }
1030
1031 // Returns the display refresh rate
1032 static double getFps(VICIIRevision rev);
1033 double getFps() const { return getFps(config.revision); }
1034
1035 // Returns the clock frequency
1036 static isize getFrequency(VICIIRevision rev);
1037 isize getFrequency() const { return getFrequency(config.revision); }
1038
1039 // Returns the number of CPU cycles performed per scanline
1040 static isize getCyclesPerLine(VICIIRevision rev);
1041 isize getCyclesPerLine() const { return getCyclesPerLine(config.revision); }
1042
1043 // Returns the number of scanline drawn per frame
1044 static isize getLinesPerFrame(VICIIRevision rev);
1045 isize getLinesPerFrame() const { return getLinesPerFrame(config.revision); }
1046
1047 // Returns the number of CPU cycles executed in one frame
1048 static isize getCyclesPerFrame(VICIIRevision rev);
1049 isize getCyclesPerFrame() const { return getCyclesPerFrame(config.revision); }
1050
1051 // Returns the number of visible scanlines in a single frame
1052 static isize numVisibleLines(VICIIRevision rev);
1053 long numVisibleLines() const { return numVisibleLines(config.revision); }
1054
1055 // Indicates if VICII is affected by the gray-dot bug
1056 static bool hasGrayCodeBug(VICIIRevision rev);
1057 bool hasGrayCodeBug() const { return hasGrayCodeBug(config.revision); }
1058
1059 // Returns true if the end of the scanline has been reached
1060 bool isLastCycleInLine(isize cycle) const;
1061
1062 // Returns true if scanline belongs to the VBLANK area
1063 bool isVBlankLine(isize line) const;
1064
1065
1066 //
1067 // Accessing the screen buffer and display properties
1068 //
1069
1070 // Returns a C64 color in 32 bit big endian RGBA format
1071 u32 getColor(isize nr) const { return rgbaTable[nr]; }
1072 u32 getColor(isize nr, Palette palette) const;
1073
1074 // Updates the RGBA values for all 16 C64 colors
1075 void updatePalette();
1076
1077private:
1078
1079 // Returns pointers to the stable textures
1080 u32 *getTexture() const;
1081 u32 *getDmaTexture() const;
1082
1083
1084 //
1085 // Accessing memory (VIC_memory.cpp)
1086 //
1087
1088public:
1089
1090 // Peeks a value from a VICII register without side effects
1091 u8 spypeek(u16 addr) const;
1092
1093 // Returns the ultimax flag
1094 u8 getUltimax() { return ultimax; }
1095
1096 // Sets the ultimax flag
1097 void setUltimax(bool value);
1098
1099 // Returns the latest value of the VICII's data bus during phi1
1100 u8 getDataBusPhi1() const { return dataBusPhi1; }
1101
1102 // Returns the latest value of the VICII's data bus during phi2
1103 u8 getDataBusPhi2() const { return dataBusPhi2; }
1104
1105 /* Schedules the VICII bank to to switched. This method is called if the
1106 * bank switch is triggered by a change of CIA2::PA or CIA2::DDRA.
1107 */
1108 void switchBank(u16 addr);
1109
1110private:
1111
1112 /* Updates the VICII bank address. The new address is computed from the
1113 * provided bank number.
1114 */
1115 void updateBankAddr(u8 bank) { bankAddr = (u16)(bank << 14); }
1116
1117 /* Updates the VICII bank address. The new address is computed from the
1118 * bits in CIA2::PA.
1119 */
1120 void updateBankAddr();
1121
1122 // Reads a value from a VICII register
1123 u8 peek(u16 addr);
1124
1125 // Writes a value into a VICII register
1126 void poke(u16 addr, u8 value);
1127
1128 // Simulates a memory access via the address and data bus
1129 u8 memAccess(u16 addr);
1130
1131 // Same as memAccess without side effects
1132 u8 memSpyAccess(u16 addr);
1133
1134 // Returns true if memAccess will read from Character ROM
1135 bool isCharRomAddr(u16 addr) const;
1136
1137 // Performs a DRAM refresh (r-access)
1138 template <u16 flags> void rAccess();
1139
1140 // Performs an idle access (i-access)
1141 template <u16 flags> void iAccess();
1142
1143 // Performs a character access (c-access)
1144 template <u16 flags> void cAccess();
1145
1146 // Performs a graphics access (g-access)
1147 template <u16 flags> void gAccess();
1148
1149 // Computes the g-access fetch address for different VICII models
1150 u16 gAccessAddr85x();
1151 u16 gAccessAddr65x();
1152
1153 /* Computes the g-access fetch address. The fetch address is influences by
1154 * both the BMM and ECM bit.
1155 */
1156 u16 gAccessAddr(bool bmm, bool ecm);
1157
1158 // Performs a sprite pointer access (p-access)
1159 template <u16 flags> void pAccess(isize sprite);
1160
1161 // Performs one of the three sprite data accesses
1162 template <u16 flags, isize sprite> void sAccess1();
1163 template <u16 flags, isize sprite> void sAccess2();
1164 template <u16 flags, isize sprite> void sAccess3();
1165
1166 /* Finalizes the sprite data access. This method is invoked one cycle after
1167 * the second and third sprite DMA has occurred.
1168 */
1169 void sFinalize(isize sprite);
1170
1171
1172 //
1173 // Handling the x and y counters
1174 //
1175
1176 /* Returns the current scanline. This value is not always identical to
1177 * the yCounter, because the yCounter is incremented with a little delay.
1178 */
1179 u16 scanline() const;
1180
1181 // Returns the current scanline cycle
1182 u8 rastercycle() const;
1183
1184 /* Indicates if yCounter needs to be reset in this scanline. PAL models
1185 * reset the yCounter in cycle 2 in the first scanline wheras NTSC models
1186 * reset the yCounter in cycle 2 in the middle of the lower border area.
1187 */
1188 bool yCounterOverflow() const { return scanline() == (isPAL ? 0 : 238); }
1189
1190 /* Matches the yCounter with the raster interrupt line and stores the
1191 * result. If a positive edge is detected, a raster interrupt is triggered.
1192 */
1193 void checkForRasterIrq();
1194
1195
1196 //
1197 // Handling the border flip flops
1198 //
1199
1200 /* "Der VIC benutzt zwei Flipflops, um den Rahmen um das Anzeigefenster
1201 * herum zu erzeugen: Ein Haupt-Rahmenflipflop und ein vertikales
1202 * Rahmenflipflop. [...]
1203 *
1204 * The flip flops are switched according to the following rules:
1205 *
1206 * 1. If the X coordinate reaches the right comparison value, the main
1207 * border flip flop is set.
1208 * 2. If the Y coordinate reaches the bottom comparison value in cycle 63,
1209 * the vertical border flip flop is set.
1210 * 3. If the Y coordinate reaches the top comparison value in cycle 63 and
1211 * the DEN bit in register $d011 is set, the vertical border flip flop
1212 * is reset.
1213 * 4. If the X coordinate reaches the left comparison value and the Y
1214 * coordinate reaches the bottom one, the vertical border flip flop is
1215 * set.
1216 * 5. If the X coordinate reaches the left comparison value and the Y
1217 * coordinate reaches the top one and the DEN bit in register $d011 is
1218 * set, the vertical border flip flop is reset.
1219 * 6. If the X coordinate reaches the left comparison value and the
1220 * vertical border flip flop is not set, the main flip flop is reset."
1221 * [C.B.]
1222 */
1223
1224 // Takes care of the vertical frame flipflop value (invoked in each cycle)
1225 void checkVerticalFrameFF();
1226
1227 // Checks the frame fliplops at left border
1228 void checkFrameFlipflopsLeft(u16 comparisonValue);
1229
1230 // Checks the frame fliplops at right border
1231 void checkFrameFlipflopsRight(u16 comparisonValue);
1232
1233 // Sets the vertical frame flipflop with a delay of one cycle
1234 void setVerticalFrameFF(bool value);
1235
1236 // Sets the main frame flipflop with a delay of one cycle
1237 void setMainFrameFF(bool value);
1238
1239 // Returns a comparison value for the border flipflops
1240 u16 leftComparisonValue() const { return isCSEL() ? 24 : 31; }
1241 u16 rightComparisonValue() const { return isCSEL() ? 344 : 335; }
1242 u16 upperComparisonValue() const { return isRSEL() ? 51 : 55; }
1243 u16 lowerComparisonValue() const { return isRSEL() ? 251 : 247; }
1244
1245
1246 //
1247 // Accessing registers
1248 //
1249
1250public:
1251
1252 // Returns the current value of the DEN (Display ENabled) bit
1253 bool DENbit() const { return GET_BIT(reg.current.ctrl1, 4); }
1254
1255 // Returns the masked CB13 bit
1256 u8 CB13() const { return memSelect & 0x08; }
1257
1258 // Returns the masked CB13/CB12/CB11 bits
1259 u8 CB13CB12CB11() const { return memSelect & 0x0E; }
1260
1261 // Returns the masked VM13/VM12/VM11/VM10 bits
1262 u8 VM13VM12VM11VM10() const { return memSelect & 0xF0; }
1263
1264 // Returns the state of the CSEL bit
1265 bool isCSEL() const { return GET_BIT(reg.current.ctrl2, 3); }
1266
1267 // Returns the state of the RSEL bit
1268 bool isRSEL() const { return GET_BIT(reg.current.ctrl1, 3); }
1269
1270
1271 //
1272 // Handling DMA lines and the display state
1273 //
1274
1275private:
1276
1277 // Returns true if the bad line condition holds
1278 bool badLineCondition() const;
1279
1280
1281 //
1282 // Interacting with the CPU
1283 //
1284
1285private:
1286
1287 // Sets the value of the BA line which is connected to the CPU's RDY pin.
1288 void updateBA(u8 value);
1289
1290 /* Indicates if a c-access can occur. A c-access can only be performed if
1291 * the BA line is down for more than 2 cycles.
1292 */
1293 bool BApulledDownForAtLeastThreeCycles() const { return baLine.delayed(); }
1294
1295 // Triggers a VICII interrupt
1296 void triggerIrq(u8 source);
1297
1298
1299 //
1300 // Handling lightpen events
1301 //
1302
1303public:
1304
1305 // Sets the value of the LP pin
1306 void setLP(bool value);
1307
1308private:
1309
1310 // Returns the coordinate of a light pen event
1311 u16 lightpenX() const;
1312 u16 lightpenY() const;
1313
1314 /* Trigger a lightpen interrupt if conditions are met. This function is
1315 * called on each negative transition of the LP pin. It latches the x and
1316 * y coordinates and immediately triggers an interrupt if a newer VICII
1317 * model is emulated. Older models trigger the interrupt later, at the
1318 * beginning of a new frame.
1319 */
1320 void checkForLightpenIrq();
1321
1322 /* Retriggers a lightpen interrupt if conditions are met. This function is
1323 * called at the beginning of each frame. If the lp line is still low at
1324 * this point of time, a lightpen interrupt is retriggered. Note that older
1325 * VICII models trigger interrupts only at this point in time.
1326 */
1327 void checkForLightpenIrqAtStartOfFrame();
1328
1329
1330 //
1331 // Sprites
1332 //
1333
1334private:
1335
1336 // Gets the depth of a sprite (will be written into the z buffer)
1337 u8 spriteDepth(isize nr) const;
1338
1339 // Compares the Y coordinates of all sprites with the yCounter
1340 u8 compareSpriteY() const;
1341
1342 /* Turns off sprite dma if conditions are met. In cycle 16, the mcbase
1343 * pointer is advanced three bytes for all dma enabled sprites. Advancing
1344 * three bytes means that mcbase will then point to the next sprite line.
1345 * When mcbase reached 63, all 21 sprite lines have been drawn and sprite
1346 * dma is switched off. The whole operation is skipped when the y expansion
1347 * flipflop is 0. This never happens for normal sprites (there is no
1348 * skipping then), but happens every other cycle for vertically expanded
1349 * sprites. Thus, mcbase advances for those sprites at half speed which
1350 * actually causes the expansion.
1351 */
1352 void turnSpriteDmaOff();
1353
1354 /* Turns on sprite dma accesses if conditions are met. This function is
1355 * called in cycle 55 and cycle 56.
1356 */
1357 void turnSpriteDmaOn();
1358
1359 /* Turns sprite display on or off. This function is called in cycle 58.
1360 */
1361 void turnSpritesOnOrOff();
1362
1363 /* Loads a sprite shift register. The shift register is loaded with the
1364 * three data bytes fetched in the previous sAccesses.
1365 */
1366 void loadSpriteShiftRegister(isize nr);
1367
1368 /* Updates the sprite shift registers. Checks if a sprite has completed
1369 * it's last DMA fetch and calls loadSpriteShiftRegister() accordingly.
1370 */
1371 void updateSpriteShiftRegisters();
1372
1373 /* Toggles expansion flipflop for vertically stretched sprites. In cycle 56,
1374 * register D017 is read and the flipflop gets inverted for all sprites with
1375 * vertical stretching enabled. When the flipflop goes down, advanceMCBase()
1376 * will have no effect in the next scanline. This causes each sprite line
1377 * to be drawn twice.
1378 */
1379 void toggleExpansionFlipflop() { expansionFF ^= reg.current.sprExpandY; }
1380
1381
1382 //
1383 // Running the device (VICII.cpp and VIC_cycles_xxx.cpp)
1384 //
1385
1386public:
1387
1388 /* Prepares VICII for drawing a new frame. This function is called prior to
1389 * the first cycle of each frame.
1390 */
1391 void beginFrame();
1392
1393 /* Prepares VICII for drawing a new scanline. This function is called
1394 * prior to the first cycle of each scanline.
1395 */
1396 void beginScanline();
1397
1398 /* Finishes up a scanline. This function is called after the last cycle
1399 * of each scanline.
1400 */
1401 void endScanline();
1402
1403 /* Finishes up a frame. This function is called after the last cycle of
1404 * each frame.
1405 */
1406 void endFrame();
1407
1408 /* Processes all time delayed actions. This function is called at the
1409 * beginning of each VICII cycle.
1410 */
1411 void processDelayedActions();
1412
1413 // Emulates a specific scanline cycle
1414 template <u16 flags> void cycle1();
1415 template <u16 flags> void cycle2();
1416 template <u16 flags> void cycle3();
1417 template <u16 flags> void cycle4();
1418 template <u16 flags> void cycle5();
1419 template <u16 flags> void cycle6();
1420 template <u16 flags> void cycle7();
1421 template <u16 flags> void cycle8();
1422 template <u16 flags> void cycle9();
1423 template <u16 flags> void cycle10();
1424 template <u16 flags> void cycle11();
1425 template <u16 flags> void cycle12();
1426 template <u16 flags> void cycle13();
1427 template <u16 flags> void cycle14();
1428 template <u16 flags> void cycle15();
1429 template <u16 flags> void cycle16();
1430 template <u16 flags> void cycle17();
1431 template <u16 flags> void cycle18();
1432 template <u16 flags> void cycle19to54();
1433 template <u16 flags> void cycle55();
1434 template <u16 flags> void cycle56();
1435 template <u16 flags> void cycle57();
1436 template <u16 flags> void cycle58();
1437 template <u16 flags> void cycle59();
1438 template <u16 flags> void cycle60();
1439 template <u16 flags> void cycle61();
1440 template <u16 flags> void cycle62();
1441 template <u16 flags> void cycle63();
1442 template <u16 flags> void cycle64();
1443 template <u16 flags> void cycle65();
1444
1445#define DRAW_SPRITES_DMA1 \
1446assert(isFirstDMAcycle); assert(!isSecondDMAcycle); \
1447if constexpr (!(flags & HEADLESS_CYCLE)) { drawSpritesSlowPath(); }
1448
1449#define DRAW_SPRITES_DMA2 \
1450assert(!isFirstDMAcycle); assert(isSecondDMAcycle); \
1451if constexpr (!(flags & HEADLESS_CYCLE)) { drawSpritesSlowPath(); }
1452
1453#define DRAW_SPRITES \
1454assert(!isFirstDMAcycle && !isSecondDMAcycle); \
1455if (spriteDisplay && !(flags & HEADLESS_CYCLE)) { drawSprites(); }
1456
1457#define DRAW_SPRITES59 \
1458if ((spriteDisplayDelayed || spriteDisplay || isSecondDMAcycle) && !(flags & HEADLESS_CYCLE)) \
1459{ drawSpritesSlowPath(); }
1460
1461#define DRAW if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder(); };
1462#define DRAW17 if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder17(); };
1463#define DRAW55 if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder55(); };
1464#define DRAW59 if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder(); };
1465
1466#define END_CYCLE \
1467dataBusPhi2 = 0xFF; \
1468xCounter += 8; \
1469bufferoffset += 8; \
1470if (unlikely(delay)) { processDelayedActions(); }
1471
1472#define END_VISIBLE_CYCLE \
1473END_CYCLE
1474
1475#define BA_LINE(x) updateBA(x);
1476
1477
1478 //
1479 // Drawing routines (VIC_draw.cpp)
1480 //
1481
1482private:
1483
1484 // Draws 8 border pixels. Invoked inside draw().
1485 void drawBorder();
1486
1487 // Draws the border pixels in cycle 17
1488 void drawBorder17();
1489
1490 // Draws the border pixels in cycle 55
1491 void drawBorder55();
1492
1493 // Draws 8 canvas pixels
1494 void drawCanvas();
1495 void drawCanvasFastPath();
1496 void drawCanvasSlowPath();
1497
1498 // Draws a single canvas pixel
1499 void drawCanvasPixel(u8 pixel, u8 mode, u8 d016);
1500
1501 // Reloads the sequencer shift register with the gAccess result
1502 void loadShiftRegister();
1503
1504 //
1505 // Drawing routines (VIC_sprites.cpp)
1506 //
1507
1508private:
1509
1510 // Draws 8 sprite pixels (see draw())
1511 void drawSprites();
1512 void drawSpritesFastPath();
1513 void drawSpritesSlowPath();
1514
1515 /* Draws all sprite pixels for a single sprite. This function is used when
1516 * the fast path is taken.
1517 */
1518 template <bool multicolor> void drawSpriteNr(isize nr, bool enable, bool active);
1519
1520 /* Draws a single sprite pixel for all sprites. This function is used when
1521 * the slow path is taken.
1522 *
1523 * pixel : pixel number (0 ... 7)
1524 * enableBits : the spriteDisplay bits
1525 * freezeBits : forces the sprites shift register to freeze temporarily
1526 */
1527 void drawSpritePixel(isize pixel, u8 enableBits, u8 freezeBits);
1528
1529 // Performs collision detection
1530 void checkCollisions();
1531
1532
1533 //
1534 // Low level drawing (pixel buffer access)
1535 //
1536
1537 // Writes a single color value into the screenbuffer
1538#define COLORIZE(index,color) \
1539emuTexturePtr[index] = rgbaTable[color];
1540
1541 // Sets a single frame pixel
1542#define SET_FRAME_PIXEL(pixel,color) { \
1543isize index = bufferoffset + pixel; \
1544COLORIZE(index, color); \
1545zBuffer[index] = DEPTH_BORDER; }
1546
1547 // Sets a single foreground pixel
1548#define SET_FG_PIXEL(pixel,color) { \
1549isize index = bufferoffset + pixel; \
1550COLORIZE(index,color) \
1551zBuffer[index] = DEPTH_FG; }
1552
1553 // Sets a single background pixel
1554#define SET_BG_PIXEL(pixel,color) { \
1555isize index = bufferoffset + pixel; \
1556COLORIZE(index,color) \
1557zBuffer[index] = DEPTH_BG; }
1558
1559 // Sets a single sprite pixel
1560#define SET_SPRITE_PIXEL(sprite,pixel,color) { \
1561isize index = bufferoffset + pixel; \
1562if (u8 depth = spriteDepth(sprite); depth <= zBuffer[index]) { \
1563if (isVisibleColumn) COLORIZE(index, color); \
1564zBuffer[index] = depth | (zBuffer[index] & 0x10); \
1565} }
1566
1567
1568 //
1569 // Debugging
1570 //
1571
1572public:
1573
1574 // Returns the current screen geometry
1575 ScreenGeometry getScreenGeometry(void) const;
1576
1577 // Returns the coordinates of a certain sprite
1578 u16 getSpriteX(int nr) const { return reg.current.sprX[nr]; }
1579 u8 getSpriteY(int nr) const { return reg.current.sprY[nr]; }
1580};
1581
1582}
static const long CLOCK_FREQUENCY
Clock frequency in Hz.
Definition Constants.h:66
static const long CLOCK_FREQUENCY
Clock frequency in Hz.
Definition Constants.h:27
static const long height
Height of the emulator texture in texels.
Definition Constants.h:105
static const long width
Width of the emulator texture in texels.
Definition Constants.h:108
VirtualC64 project namespace.
Definition CmdQueue.cpp:16
SCREEN_GEOMETRY ScreenGeometry
Type alias.
Definition VICIITypes.h:157
@ OPT_VICII_REVISION
Chip revision.
Definition OptionTypes.h:43
@ OPT_VICII_POWER_SAVE
Enable fast-paths.
Definition OptionTypes.h:45
@ OPT_VICII_SB_COLLISIONS
Check for sprite-background collisions.
Definition OptionTypes.h:50
@ OPT_GLUE_LOGIC
VICII glue-logic type.
Definition OptionTypes.h:101
@ OPT_VICII_HIDE_SPRITES
Hide some sprites.
Definition OptionTypes.h:46
@ OPT_VICII_SS_COLLISIONS
Check for sprite-sprite collisions.
Definition OptionTypes.h:49
@ OPT_VICII_GRAY_DOT_BUG
Emulate gray-dot bug.
Definition OptionTypes.h:44