
                The MOS 6567/6569 video controller (VIC-II)
                  and its application in the Commodore 64

                            by Christian Bauer
                              <www.cebix.net>

                                2024-09-29



Contents
--------

1. Introduction
2. The architecture of the Commodore 64
2.1. Overview
2.2. 6510 processor
2.3. 6567/6569 graphics chip
2.4. Memory
2.4.1. Memory map as seen by the 6510
2.4.2. Memory map as seen by the VIC
2.4.3. Memory access of 6510 and VIC
3. Description of the VIC
3.1. Block diagram
3.2. Registers
3.3. Color palette
3.4. Display generation and display window dimensions
3.5. Bad Lines
3.6. Memory access
3.6.1. The X coordinates
3.6.2. Access types
3.6.3. Timing of a raster line
3.7. Text/bitmap display
3.7.1. Idle state / display state
3.7.2. VC and RC
3.7.3. Graphics modes
3.7.3.1. Standard text mode (ECM/BMM/MCM=0/0/0)
3.7.3.2. Multicolor text mode (ECM/BMM/MCM=0/0/1)
3.7.3.3. Standard bitmap mode (ECM/BMM/MCM=0/1/0)
3.7.3.4. Multicolor bitmap mode (ECM/BMM/MCM=0/1/1)
3.7.3.5. ECM text mode (ECM/BMM/MCM=1/0/0)
3.7.3.6. Invalid text mode (ECM/BMM/MCM=1/0/1)
3.7.3.7. Invalid bitmap mode 1 (ECM/BMM/MCM=1/1/0)
3.7.3.8. Invalid bitmap mode 2 (ECM/BMM/MCM=1/1/1)
3.7.3.9. Idle state
3.8. Sprites
3.8.1. Memory access and display
3.8.2. Priority and collision detection
3.9. The border units
3.10. Display Enable
3.11. Lightpen
3.12. VIC interrupts
3.13. DRAM refresh
3.14. Effects and applications
3.14.1. Hyperscreen
3.14.2. FLD
3.14.3. FLI
3.14.4. Linecrunch
3.14.5. Doubled text lines
3.14.6. DMA delay / VSP
3.14.7. Sprite stretching / Sprite crunch
4. The addresses 0 and 1 and the $de00 area
5. Revision history

Appendix A: Bibliography
Appendix B: Acknowledgments



1. Introduction
---------------

This paper is an attempt to summarize the results of various people's
examinations of the graphics chip "6567/6569 Video Interface Controller
(VIC-II)" (simply called "VIC" in the following) which is used in the
legendary Commodore 64, and to provide a complete reference to its specified
and unspecified properties. It is primarily intended for C64 programmers and
authors of C64 emulators, but should also be interesting to "outsiders"
interested in hardware design and programming, and utilizing a computer up
to its last bits. For this purpose, some general information (e.g. the C64
memory map) already known to experienced C64 programmers has been included
as well.

The description of the unspecified properties is based on tests done by
Marko Mäkelä, Andreas Boose, Pasi Ojala, Wolfgang Lorenz and myself (not to
mention numerous others) during the 1990s. It also covers internal registers
and workings of the VIC. As no schematics of the VIC are available it can of
course only be speculative, but in all cases a descriptive model has been
chosen that explains the observed phenomena with the minimally required
circuitry. E.g. for the video matrix counter (VC), a model with two simple
counters was given preference to a more elaborate one with a +40 adder.

Although some measurements were done with an oscilloscope directly on the
chip, most insights have been gathered via test programs on the C64, and by
comparing them with the implementation in single cycle emulations like
"Frodo".


2. The architecture of the Commodore 64
---------------------------------------

This chapter gives an overview of the basic hardware architecture of the C64
and the integration of the VIC into the system.

2.1. Overview
-------------

The C64 basically consists of the following units:

 · 6510 8-bit microprocessor
 · 6567/6569 VIC-II graphics chip
 · 6581 SID sound chip
 · Two 6526 CIA I/O chips
 · 64KB DRAM (64K*8 bit) main memory
 · 0.5KB SRAM (1K*4 bit) Color RAM
 · 16KB ROM (16K*8 bit) for operating system and BASIC interpreter
 · 4KB ROM (4K*8 bit) character generator

Most chips are manufactured in NMOS technology.

2.2. 6510 processor
-------------------

The 6510 microprocessor [1] has an 8-bit data bus and a 16-bit address bus,
and is object-code compatible with the famous 6502. It has two external
interrupt inputs, one maskable (IRQ) and one non-maskable (NMI), and as a
special feature a 6-bit wide bidirectional I/O port. It is clocked at
approximately 1 MHz in the C64.

Important signals:

ϕ2     Processor clock output
       This clock signal is the reference for the entire bus timing. Its
       frequency is 1022.7 kHz (NTSC models) or 985.248 kHz (PAL models).
       One period of this signal corresponds to one clock cycle consisting
       of two phases: ϕ2 is low in the first phase and high in the second
       phase (hence the name 'ϕ2' for "phase 2"). The 6510 only accesses the
       bus in the second clock phase, the VIC normally only in the first
       phase.

ϕ0     Processor clock input
       This signal, with the same frequency as ϕ2, is generated by the
       VIC (see section 2.3.) and used to derive the ϕ2 clock.

R/W    This signal indicates a read (R/W high) or write (R/W low) bus
       access.

IRQ    If this input is held low an interrupt sequence is triggered, unless
       interrupts are masked with the interrupt mask bit in the processor
       status register. The interrupt sequence begins at least two clock
       cycles later at the start of the next instruction. With this pin, the
       VIC can trigger an interrupt in the processor. Interrupts are only
       recognized if the RDY line is high.

RDY    If this line is low during a read access, the processor stops with
       the address lines reflecting the current address being fetched. It
       is ignored during write accesses. In the C64, RDY is used to stop
       the processor if the VIC needs additional bus cycles for character
       pointer and sprite data accesses. It is connected to the BA signal
       on the VIC.

AEC    This pin tri-states the address lines. This is used for making the
       processor address bus inactive during VIC accesses. The signal is
       connected to the AEC output on the VIC.

P0-P5  This is the built-in 6-bit I/O port. Each line can be individually
       programmed as input or output. A data direction register and a data
       register are internally mapped to addresses 0 and 1, respectively.
       You might therefore expect that the processor cannot access the RAM
       addresses 0 and 1, as they are overlaid by the I/O port, but more
       on this in chapter 4...

2.3. 6567/6569 graphics chip
----------------------------

The 656* series graphics chips by MOS Technologies were originally designed
to be used in video games and graphics terminals. But as the sales in these
markets had been rather poor, Commodore decided to use the chips when they
were planning to make their own home computers.

In the C64, the "Video Interface Controller II (VIC-II)" [2] is used,
featuring 3 text (or tile) based video modes (40x25 characters with 8x8
pixels each) and 2 bitmap based video modes (320x200 pixels), 8 hardware
sprites and a fixed palette of 16 colors. It can manage up to 16KB of
dynamic RAM, including the generation of RAS and CAS and handling the RAM
refresh, and also has a light pen input and interrupt capabilities.

Two VIC types appear in the C64: The 6567 in NTSC machines and the 6569 in
PAL machines. There are several mask steppings of both types, but the
differences are mostly negligible with the exception of the 6567R56A. Newer
C64 versions are employing the functionally equivalent chips 8562 (NTSC) and
8565 (PAL). In the following, only 6567/6569 will be mentioned, but all
information is also applicable to the 856* chips. There is also a 6566
designed to be connected to static RAM but this one was never used in C64s
(it was used, however, in the somewhat similar Commodore MAX computer).

Important signals:

A0-A13  The 14-bit video address bus used by the VIC to address 16KB of
        memory. The address bits A0-A5 and A8-A13 are multiplexed in pairs
        (i.e. A0/A8, A1/A9 etc.) on one pin each. The bits A6-A11 are
        (additionally) available on separate lines.

D0-D11  A 12-bit wide data bus over which the VIC accesses the memory. The
        lower 8 bits are connected to the main memory and the processor
        data bus, the upper 4 bits are connected to a special 4 bit wide
        static memory (1024 addresses, A0-A9) used for storing color
        information, the Color RAM.

IRQ     This output is wired to the IRQ input on the processor and makes it
        possible for the VIC to trigger interrupts. The VIC has four
        interrupt sources: On reaching a certain raster line (raster
        interrupt), on the collision of two or more sprites, on the
        collision of sprites with graphics data and on a negative edge on
        the light pen input.

BA      With this signal, the VIC indicates that the bus is available to
        the processor during the second clock phase (ϕ2 high). BA is
        normally high, as the VIC usually accesses the bus during the first
        phase only. But for the character pointer and sprite data accesses,
        the VIC also needs the bus during the second phase. In this case, BA
        goes low three cycles before the VIC access. After that, AEC remains
        low during the second phase and the VIC performs its accesses. Why
        three cycles? BA is connected to the RDY line of the processor as
        mentioned, but this line is ignored on write accesses (the CPU can
        only be interrupted on reads), and the 6510 never does more than
        three writes in sequence (see [5]).

AEC     This pin is wired to the processor signal with the same name (see
        above). It reflects the state of the data and address line drivers
        of the VIC. If AEC is high, they are in tri-state. AEC is normally
        low during the first clock phase (ϕ2 low) and high during the second
        phase so the VIC can access the bus during the first phase and the
        6510 during the second phase. If the VIC also needs the bus in the
        second phase, AEC remains low.

LP      This input is intended for connecting a light pen. On a negative
        edge, the current position of the raster beam is latched to the
        registers LPX and LPY. As this pin shares a line with the keyboard
        matrix, it can also be accessed by software.

ϕIN     This is the feed for the pixel clock of 8.18 MHz (NTSC) or 7.88 MHz
        (PAL) that is generated from the crystal frequency. Eight pixels
        are displayed per bus clock cycle (ϕ2).

ϕ0      From the pixel clock on ϕIN, the VIC generates the system clock of
        1.023 MHz (NTSC) or 0.985 MHz (PAL) by dividing ϕIN by eight. It is
        available on this pin and fed into the processor which in turn
        generates the signal ϕ2 from it.

ϕCOLOR	This input receives a 14.31818 MHz (NTSC) or 17.734475 MHz (PAL)
        signal from which the VIC derives its color output signal. Its
        frequency corresponds to four times the NTSC or PAL color burst
        signals of 3.579545 MHz and 4.43361875 MHz, respectively.

S/LUM	This pin outputs the horizontal and vertical sync signals and the
        luminosity information for the image produced by the VIC. The VIC
        does not support interlace and always outputs a progressive image.

COLOR   This pin outputs the composite color information for the image,
        including the color burst signal.

2.4. Memory
-----------

Three memory areas in the C64 are involved with the graphics:

 · The 64KB main memory
 · The 1K*4 bit Color RAM
 · The 4KB character generator ROM (Char ROM)

In the following two sections we explain how these memory areas share the
address space as seen by the CPU and the VIC. After that, we will cover the
basics of memory access and DRAM handling.

2.4.1 Memory map as seen by the 6510
------------------------------------

The 6510 can address 64KB linearly with its 16 address lines. With the aid
of a special PAL chip in the C64, many different memory configurations can
be used, controlled via the 6510 I/O port lines and additional signals on
the expansion port (see [3]). Only the standard configuration will be
discussed here as the other configurations don't change the position of the
different areas. They only map in additional areas of the main memory.

This is the memory map as seen by the 6510:


                               The area at $d000-$dfff with
                                  CHAREN=1     CHAREN=0

 $ffff +--------------+  /$e000 +----------+  +----------+
       |  Kernal ROM  | /       |  I/O  2  |  |          |
 $e000 +--------------+/  $df00 +----------+  |          |
       |I/O, Char ROM |         |  I/O  1  |  |          |
 $d000 +--------------+\  $de00 +----------+  |          |
       |     RAM      | \       |  CIA  2  |  |          |
 $c000 +--------------+  \$dd00 +----------+  |          |
       |  Basic ROM   |         |  CIA  1  |  |          |
 $a000 +--------------+   $dc00 +----------+  | Char ROM |
       |              |         |Color RAM |  |          |
       .     RAM      .         |          |  |          |
       .              .   $d800 +----------+  |          |
       |              |         |   SID    |  |          |
 $0002 +--------------+         |registers |  |          |
       | I/O port DR  |   $d400 +----------+  |          |
 $0001 +--------------+         |   VIC    |  |          |
       | I/O port DDR |         |registers |  |          |
 $0000 +--------------+   $d000 +----------+  +----------+


Basically, the 64KB main memory can be accessed in a linear fashion, but
they are overlaid by ROM and register areas at several positions. A write
access to a ROM area will change the byte in the RAM lying "under" the ROM.
The 6510 I/O port is mapped to addresses $0000 (for the data direction
register) and $0001 (for the data register).

In the area at $d000-$dfff you can switch between the I/O chip registers and
the Color RAM, or the character generator ROM, with the signal CHAREN which
is bit 2 of the 6510 I/O port. The Color RAM is mapped at $d800-$dbff and
connected to the lower 4 data bits. The upper 4 bits are open and produce
"random" values on reading. The two areas named "I/O 1" and "I/O 2" are
reserved for expansion cards and also open under normal circumstances.
Hence, a read access will fetch "random" values here too. As we will explain
in chapter 4 these values are not fully random. Reading from open addresses
fetches the last byte read by the VIC on many C64s.

The 47 registers of the VIC are mapped in at $d000. Due to the incomplete
address decoding, they are mirrored every 64 bytes in the area $d000-$d3ff.

2.4.2 Memory map as seen by the VIC
-----------------------------------

The VIC has only 14 address lines, so it can only address 16KB of memory. It
can nevertheless access the entire 64KB of main memory because the two
missing address bits are provided by one of the CIA I/O chips (they are the
inverted bits 0 and 1 of port A of CIA 2). With these you can select one of
four 16KB banks for the VIC at a time.

The (extended) memory map as seen by the VIC looks like this:


 $ffff +----------+   --
       |          |
       |          |
       |          |
       |   RAM    | Bank 3
       |          |
       |          |
       |          |
 $c000 +----------+   --
       |          |
       |   RAM    |
       |          |
 $a000 +----------+ Bank 2
       | Char ROM |
 $9000 +----------+
       |   RAM    |
 $8000 +----------+   --
       |          |
       |          |
       |          |
       |   RAM    | Bank 1
       |          |
       |          |
       |          |
 $4000 +----------+   --
       |          |
       |   RAM    |
       |          |
 $2000 +----------+ Bank 0
       | Char ROM |
 $1000 +----------+
       |   RAM    |
 $0000 +----------+   --


The Char ROM is mapped in at the VIC addresses $1000-$1fff in banks 0 and
2 (it appears at $9000 in the above diagram, but remember that the VIC
doesn't know about the two address bits generated by the CIA. From the
VIC's point of view, the Char ROM is at $1000-$1fff also in bank 2).

The attentive reader will already have noticed that the Color RAM doesn't
seem to appear anywhere. But as explained earlier, the VIC has a 12-bit data
bus of which the upper 4 bits are connected to the Color RAM. Generally
speaking, the sole purpose of the upper 4 bits of the VIC data bus is to
read from the Color RAM. The Color RAM is addressed by the lower 10 bits of
the VIC address bus and is therefore available in all banks at all
addresses.

2.4.3 Memory access of the 6510 and VIC
---------------------------------------

The VIC only performs read accesses to memory, while the 6510 performs both
reads and writes. 6510 and VIC are both based on relatively simple
hard-wired designs, and both chips do a memory access in EVERY clock cycle,
even if unnecessary. For example, if the processor is busy executing an
internal operation such as calculating an indexed address, that doesn't
actually require an access to memory, it nevertheless performs a read access
and then discards the read byte.

There are no wait states, no internal caches and no sophisticated access
protocols for the bus as seen in more modern computer designs. Every access
is done in a single cycle.

The VIC generates the clock frequencies for the system bus and the RAS and
CAS signals for accessing the dynamic RAM, for both the processor and the
VIC itself. It has primary control over the bus and may "stun" the processor
at times when it needs additional cycles for memory accesses. Additionally,
the VIC takes care of the DRAM refresh by reading from 5 refresh addresses
in each raster line.

The division of accesses between 6510 and VIC is basically static: Each
clock cycle (one period of the ϕ2 signal) consists of two phases. The VIC
accesses in the first phase (ϕ2 low), the processor in the second phase (ϕ2
high). The AEC signal closely follows ϕ2. That way the 6510 and VIC can
usually alternate their memory use without disturbing each other.

However, the VIC sometimes needs more cycles than it has available via this
scheme. This is the case when the VIC accesses the character pointers and
the sprite data. In the first case it needs 40 additional cycles, in the
second case it needs 2 cycles per sprite. BA will then go low 3 cycles
before the VIC takes over the bus completely (3 cycles is the maximum number
of successive write accesses of the 6510). After 3 cycles, AEC stays low
during the second clock phase so that the VIC can output its addresses.

The following diagram illustrates the process of the take-over:

       _ _ _ _ _ _ _ _ _ _ _ _ _    _ _ _ _ _ _ _ _ _ _ _ _ _
 ϕ2   _ _ _ _ _ _ _ _ _ _ _ _ _ ..._ _ _ _ _ _ _ _ _ _ _ _ _
      ______________                       __________________
 BA                 ____________...________
       _ _ _ _ _ _ _ _ _ _                  _ _ _ _ _ _ _ _ _
 AEC  _ _ _ _ _ _ _ _ _ _ ______..._________ _ _ _ _ _ _ _ _

 Chip VPVPVPVPVPVPVPVpVpVpVVVVVV...VVVVVVVVVPVPVPVPVPVPVPVP

           1       |  2  |       3        |       4
         Normal    |Take-| VIC has taken  |  VIC releases
      bus activity |over | over the bus   |    the bus


The line "Chip" designates which chip is just accessing the bus (as said
before, there is an access in every cycle). "V" stands for the VIC, "P" for
the 6510. The cycles designated with "p" are accesses of the 6510 that are
only performed if they are write accesses, and the first "p" read access
stops the 6510. On a "p" read access the processor addresses are still
output on the bus because AEC is still high.

The diagram describes the normal process of a bus take-over. By modifying
VIC register $d011 in certain ways it is possible to force a bus take-over
at unusual times. This is explained in chapter 3 together with the complete
bus timing of a VIC raster line.


3. Description of the VIC
-------------------------

This chapter explains the individual function units in the VIC, their way of
working and their unspecified behavior, and the insights into the internal
functions of the VIC that can be gained by that.

3.1. Block diagram
------------------

The following block diagram gives an overview over the internal structure
of the VIC and the independently working function units:


 IRQ <---------------------------------+
                                       |
            +---------------+ +-----------------+
            |Refresh counter| | Interrupt logic |<----------------------+
            +---------------+ +-----------------+                       |
        +-+    |               ^                                        |
  A     |M|    v               |                                        |
  d     |e|   +-+    +--------------+  +-------+                        |
  d     |m|   |A|    |Raster counter|->| VC/RC |                        |
  r     |o|   |d| +->|      X/Y     |  +-------+                        |
  . <==>|r|   |d| |  +--------------+      |                            |
  +     |y|   |r| |     | | |              |                            |
  d     | |   |.|<--------+----------------+ +------------------------+ |
  a     |i|   |g|===========================>|40×12 bit video matrix-/| |
  t     |n|<=>|e| |     |   |                |       color line       | |
  a     |t|   |n| |     |   |                +------------------------+ |
        |e|   |e| |     |   |                            ||             |
        |r|   |r| |     |   | +----------------+         ||             |
 BA  <--|f|   |a|============>|8×24 bit sprite |         ||             |
        |a|   |t|<----+ |   | |  data buffers  |         ||             |
 AEC <--|c|   |o| |   | v   | +----------------+         ||             |
        |e|   |r| | +-----+ |         ||                 ||             |
        +-+   +-+ | |MC0-7| |         \/                 \/             |
                  | +-----+ |  +--------------+   +--------------+      |
                  |         |  | Sprite data  |   |Graphics data |      |
        +---------------+   |  |  sequencer   |   |  sequencer   |      |
 RAS <--|               |   |  +--------------+   +--------------+      |
 CAS <--|Clock generator|   |              |         |                  |
 ϕ0  <--|               |   |              v         v                  |
        +---------------+   |       +-----------------------+           |
                ^           |       |          MUX          |           |
                |           |       | Sprite priorities and |-----------+
 ϕIN -----------+           |       |  collision detection  |
                            |       +-----------------------+
   VC: Video Matrix Counter |                   |
                            |                   v
   RC: Row Counter          |            +-------------+
                            +----------->| Border unit |
   MC: MOB Data Counter     |            +-------------+
                            |                   |
                            v                   v
                    +----------------+  +----------------+
                    |Sync generation |  |Color generation|<-------- ϕCOLOR
                    +----------------+  +----------------+
                                   |      |
                                   v      v
                                 Video output
                               (S/LUM and COLOR)


The lightpen unit is not shown.

As you can see, the "Raster counter X/Y" plays a central role. This is no
surprise as the complete screen display and all bus accesses are
synchronized to it.

It is important to note that the units for display and for memory access are
separate from each other for the sprites as well as for the graphics. There
is a data buffer between the two units that holds the read graphics data and
buffers it for the display circuits. In the normal operation of the VIC, the
functions of the two units are so closely tied to each other that they
appear like a single function block. By appropriate programming, however,
you can decouple the circuits and, for example, display graphics without
previously having read data (in this case, the data which is still in the
buffer is displayed).

3.2. Registers
--------------

The VIC has 47 read/write registers for the processor to control its
functions:

 #| Adr.  |Bit7|Bit6|Bit5|Bit4|Bit3|Bit2|Bit1|Bit0| Function
--+-------+----+----+----+----+----+----+----+----+------------------------
 0| $d000 |                  M0X                  | X coordinate sprite 0
--+-------+---------------------------------------+------------------------
 1| $d001 |                  M0Y                  | Y coordinate sprite 0
--+-------+---------------------------------------+------------------------
 2| $d002 |                  M1X                  | X coordinate sprite 1
--+-------+---------------------------------------+------------------------
 3| $d003 |                  M1Y                  | Y coordinate sprite 1
--+-------+---------------------------------------+------------------------
 4| $d004 |                  M2X                  | X coordinate sprite 2
--+-------+---------------------------------------+------------------------
 5| $d005 |                  M2Y                  | Y coordinate sprite 2
--+-------+---------------------------------------+------------------------
 6| $d006 |                  M3X                  | X coordinate sprite 3
--+-------+---------------------------------------+------------------------
 7| $d007 |                  M3Y                  | Y coordinate sprite 3
--+-------+---------------------------------------+------------------------
 8| $d008 |                  M4X                  | X coordinate sprite 4
--+-------+---------------------------------------+------------------------
 9| $d009 |                  M4Y                  | Y coordinate sprite 4
--+-------+---------------------------------------+------------------------
10| $d00a |                  M5X                  | X coordinate sprite 5
--+-------+---------------------------------------+------------------------
11| $d00b |                  M5Y                  | Y coordinate sprite 5
--+-------+---------------------------------------+------------------------
12| $d00c |                  M6X                  | X coordinate sprite 6
--+-------+---------------------------------------+------------------------
13| $d00d |                  M6Y                  | Y coordinate sprite 6
--+-------+---------------------------------------+------------------------
14| $d00e |                  M7X                  | X coordinate sprite 7
--+-------+---------------------------------------+------------------------
15| $d00f |                  M7Y                  | Y coordinate sprite 7
--+-------+----+----+----+----+----+----+----+----+------------------------
16| $d010 |M7X8|M6X8|M5X8|M4X8|M3X8|M2X8|M1X8|M0X8| MSBs of X coordinates
--+-------+----+----+----+----+----+----+----+----+------------------------
17| $d011 |RST8| ECM| BMM| DEN|RSEL|    YSCROLL   | Control register 1
--+-------+----+----+----+----+----+--------------+------------------------
18| $d012 |                 RASTER                | Raster counter
--+-------+---------------------------------------+------------------------
19| $d013 |                  LPX                  | Light pen X
--+-------+---------------------------------------+------------------------
20| $d014 |                  LPY                  | Light pen Y
--+-------+----+----+----+----+----+----+----+----+------------------------
21| $d015 | M7E| M6E| M5E| M4E| M3E| M2E| M1E| M0E| Sprite enabled
--+-------+----+----+----+----+----+----+----+----+------------------------
22| $d016 |  - |  - | RES| MCM|CSEL|    XSCROLL   | Control register 2
--+-------+----+----+----+----+----+----+----+----+------------------------
23| $d017 |M7YE|M6YE|M5YE|M4YE|M3YE|M2YE|M1YE|M0YE| Sprite Y expansion
--+-------+----+----+----+----+----+----+----+----+------------------------
24| $d018 |VM13|VM12|VM11|VM10|CB13|CB12|CB11|  - | Memory pointers
--+-------+----+----+----+----+----+----+----+----+------------------------
25| $d019 | IRQ|  - |  - |  - | ILP|IMMC|IMBC|IRST| Interrupt register
--+-------+----+----+----+----+----+----+----+----+------------------------
26| $d01a |  - |  - |  - |  - | ELP|EMMC|EMBC|ERST| Interrupt enabled
--+-------+----+----+----+----+----+----+----+----+------------------------
27| $d01b |M7DP|M6DP|M5DP|M4DP|M3DP|M2DP|M1DP|M0DP| Sprite data priority
--+-------+----+----+----+----+----+----+----+----+------------------------
28| $d01c |M7MC|M6MC|M5MC|M4MC|M3MC|M2MC|M1MC|M0MC| Sprite multicolor
--+-------+----+----+----+----+----+----+----+----+------------------------
29| $d01d |M7XE|M6XE|M5XE|M4XE|M3XE|M2XE|M1XE|M0XE| Sprite X expansion
--+-------+----+----+----+----+----+----+----+----+------------------------
30| $d01e | M7M| M6M| M5M| M4M| M3M| M2M| M1M| M0M| Sprite-sprite collision
--+-------+----+----+----+----+----+----+----+----+------------------------
31| $d01f | M7D| M6D| M5D| M4D| M3D| M2D| M1D| M0D| Sprite-data collision
--+-------+----+----+----+----+----+----+----+----+------------------------
32| $d020 |  - |  - |  - |  - |         EC        | Border color
--+-------+----+----+----+----+-------------------+------------------------
33| $d021 |  - |  - |  - |  - |        B0C        | Background color 0
--+-------+----+----+----+----+-------------------+------------------------
34| $d022 |  - |  - |  - |  - |        B1C        | Background color 1
--+-------+----+----+----+----+-------------------+------------------------
35| $d023 |  - |  - |  - |  - |        B2C        | Background color 2
--+-------+----+----+----+----+-------------------+------------------------
36| $d024 |  - |  - |  - |  - |        B3C        | Background color 3
--+-------+----+----+----+----+-------------------+------------------------
37| $d025 |  - |  - |  - |  - |        MM0        | Sprite multicolor 0
--+-------+----+----+----+----+-------------------+------------------------
38| $d026 |  - |  - |  - |  - |        MM1        | Sprite multicolor 1
--+-------+----+----+----+----+-------------------+------------------------
39| $d027 |  - |  - |  - |  - |        M0C        | Color sprite 0
--+-------+----+----+----+----+-------------------+------------------------
40| $d028 |  - |  - |  - |  - |        M1C        | Color sprite 1
--+-------+----+----+----+----+-------------------+------------------------
41| $d029 |  - |  - |  - |  - |        M2C        | Color sprite 2
--+-------+----+----+----+----+-------------------+------------------------
42| $d02a |  - |  - |  - |  - |        M3C        | Color sprite 3
--+-------+----+----+----+----+-------------------+------------------------
43| $d02b |  - |  - |  - |  - |        M4C        | Color sprite 4
--+-------+----+----+----+----+-------------------+------------------------
44| $d02c |  - |  - |  - |  - |        M5C        | Color sprite 5
--+-------+----+----+----+----+-------------------+------------------------
45| $d02d |  - |  - |  - |  - |        M6C        | Color sprite 6
--+-------+----+----+----+----+-------------------+------------------------
46| $d02e |  - |  - |  - |  - |        M7C        | Color sprite 7
--+-------+----+----+----+----+-------------------+------------------------

Notes:

 · The bits marked with '-' are not connected and yield "1" on reading.
 · The VIC registers are repeated every 64 bytes in the area $d000-$d3ff,
   i.e. register 0 appears on addresses $d000, $d040, $d080 etc.
 · The unused addresses $d02f-$d03f yield $ff on reading, a write access is
   ignored.
 · The registers $d01e and $d01f cannot be written and are automatically
   cleared on reading.
 · The RES bit (bit 5) of register $d016 has no known function on the VIC
   types 6567/6569. On the 6566, this bit is used to stop the VIC.
 · Bit 7 in register $d011 (RST8) is bit 8 of register $d012. Together they
   are called "RASTER" in the following. A write access to these bits sets
   the comparison line for the raster interrupt (see section 3.12.).

3.3. Color palette
------------------

The VIC has a hard-wired palette of 16 colors that are encoded in 4 bits:

  0 black
  1 white
  2 red
  3 cyan
  4 pink
  5 green
  6 blue
  7 yellow
  8 orange
  9 brown
 10 light red
 11 dark gray
 12 medium gray
 13 light green
 14 light blue
 15 light gray

The VIC does not use RGB color generation like modern graphics chips but is
designed for analog color television, which represents color information as
the phase shift and amplitude of a sinusoidal signal that is output on the
COLOR pin of the VIC.

Internally, the VIC generates this color signal by mixing a sine and a
cosine wave, both derived from the ϕCOLOR input of the chip [6]. The
amplitudes of these two signals are modulated according to the individual
color value in order to produce the desired phase and amplitude of the
output signal.

There is some difference in the luminance levels generated for each of the
16 different colors depending on the VIC chip revision. Older revisions
(6569R1) produced five distinct levels, while newer version increased this
to nine levels. Presumably this was done to make the colors more
distinguishable on monochrome displays.

See [8] for an in-depth description and reverse engineering of the VIC color
palette.

3.4. Display generation and display window dimensions
-----------------------------------------------------

As usual for controlling CRT displays, the VIC builds up the video frame
line by line. The line number and the number of clock cycles per line are
constant for each VIC type. The VIC works character-based, with every
character consisting of a matrix of 8×8 pixels, so a text line is made up of
8 pixel lines. 40×25 text characters are displayed in the text based modes,
and 320×200 or 160×200 pixels in the bitmap modes.

In this article, we will specify a position on the screen using the raster
line number as the Y coordinate (RASTER, register $d011/$d012) and an X
coordinate that corresponds to the sprite coordinate system. When specifying
the time of a VIC memory access or an internal operation in the VIC, we will
use the raster line number as the Y coordinate and the number of the clock
cycle (and sometimes also the clock phase) within that line as the X
coordinate. As previously mentioned, 8 pixels make one clock cycle, so the
specification of a sprite X coordinate is eight times more precise than that
of a cycle number.

The VIC displays its main graphics in an unmovable window in the middle of
the visible screen area, the "display window". The area outside the display
window is covered by the screen border and is displayed in the border color
(EC, register $d020). You can also turn off the border partially or
completely with some programming tricks (see section 3.9.); then it becomes
apparent that the display window is part of a "display column" which is the
linear extension of the display window to the top and bottom. With this you
can divide the border into an upper/lower border and a left/right border.
The visible screen area is surrounded by blanking intervals in which the
video signal is turned off and in which the raster beam returns to the start
of the next line or the start of the frame, respectively.

The following figure (not to scale) illustrates the last paragraph:


                Visible pixels/line
     ____________________|___________________
    /                                        \

+------------------------------------------------+  <- Raster line 0 (6569)
|       .                                .       |
|       .   Vertical blanking interval   .       |
|       .                                .       |
+---+---+--------------------------------+---+---+  \
|   |   |                                |   |   |  |
| H |   |          Upper border          |   | H |  |
| o |   |                                |   | o |  |
| r |   +--------------------------------+   | r |  |
| i |   |                                |   | i |  |
| z |   |                                |   | z |  |
| o |   |                                |   | o |  |
| n |   |                                |   | n |  |
| t |   |                                |   | t |  |
| a |   |                                | r | a |  |
| l | l |                                | i | l |  |
|   | e |                                | g |   |  |
| b | f |                                | h | b |  |
| l | t |                                | t | l |  |
| a |   |         Display window         |   | a |  |- Visible lines
| n | b |                                | b | n |  |
| k | o |                                | o | k |  |
| i | r |                                | r | i |  |
| n | d |                                | d | n |  |
| g | e |                                | e | g |  |
|   | r |                                | r |   |  |
| i |   |                                |   | i |  |
| n |   |                                |   | n |  |
| t |   |                                |   | t |  |
| e |   |                                |   | e |  |
| r |   |                                |   | r |  |
| v |   +--------------------------------+   | v |  |
| a |   |                                |   | a |  |
| l |   |          Lower border          |   | l |  | <- Raster line 0 (6567)
|   |   |                                |   |   |  |
+---+---+--------------------------------+---+---+  /
|       .                                .       |
|       .   Vertical blanking interval   .       |
|       .                                .       |
+------------------------------------------------+
 
      ^ \________________________________/
      |                 |
      |           Display column
      |
 X coordinate 0


The height and width of the display window can be separately set to two
different values with the bits RSEL and CSEL in the registers $d011 and
$d016:

 RSEL|  Display window height   | First line  | Last line
 ----+--------------------------+-------------+----------
   0 | 24 text lines/192 pixels |   55 ($37)  | 246 ($f6)
   1 | 25 text lines/200 pixels |   51 ($33)  | 250 ($fa)

 CSEL|   Display window width   | First X coo. | Last X coo.
 ----+--------------------------+--------------+------------
   0 | 38 characters/304 pixels |   31 ($1f)   |  334 ($14e)
   1 | 40 characters/320 pixels |   24 ($18)   |  343 ($157)

If RSEL=0 the upper and lower border each grow by 4 pixels into the display
window. If CSEL=0 the left border grows by 7 pixels and the right one by 9
pixels. The position of the display window and its resolution do not change:
RSEL/CSEL only switch the starting and ending position of the border
display. The size of the video matrix also stays constantly at 40×25
characters.

With XSCROLL (bits 0-2 of register $d016) and YSCROLL (bits 0-2 of register
$d011) the position of the graphics inside the display window can be shifted
in single-pixel units up to 7 pixels to the right and to the bottom. This
can be used for soft scrolling. The position of the display window itself
doesn't change. To align the graphics with the window, X/YSCROLL have to be
set to 0 and 3 for 25 lines/40 columns, and to 7 each for 24 lines/38
columns.

The dimensions of the video display for the different VIC types are as
follows:

          | Video  | # of  | Visible | Cycles/ |  Visible
   Type   | system | lines |  lines  |  line   | pixels/line
 ---------+--------+-------+---------+---------+------------
 6567R56A | NTSC-M |  262  |   234   |   64    |    411
  6567R8  | NTSC-M |  263  |   235   |   65    |    418
   6569   |  PAL-B |  312  |   284   |   63    |    403

          | First  |  Last  |              |   First    |   Last
          | vblank | vblank | First X coo. |  visible   |  visible
   Type   |  line  |  line  |  of a line   |   X coo.   |   X coo.
 ---------+--------+--------+--------------+------------+-----------
 6567R56A |   13   |   40   |  412 ($19c)  | 488 ($1e8) | 388 ($184)
  6567R8  |   13   |   40   |  412 ($19c)  | 489 ($1e9) | 396 ($18c)
   6569   |  300   |   15   |  404 ($194)  | 480 ($1e0) | 380 ($17c)

If you are wondering why the first visible X coordinates seem to come after
the last visible ones: This is because as the reference point that marks the
beginning of a raster line, we have chosen the occurrence of the raster IRQ
which doesn't coincide with X coordinate 0 but with the coordinate given as
"First X coo. of a line". The X coordinates run up to $1ff (only $1f7 on the
6569) within a line, then follows X coordinate 0. This is explained in more
detail in the explanation of the structure of a raster line.

3.5. Bad Lines
--------------

As already mentioned, the VIC needs 40 additional bus cycles when fetching
the character pointers (i.e. the character codes of one text line from the
video matrix), because the 63-65 bus cycles available for transparent access
by the VIC during the first clock phases within a line are not sufficient to
read both the character pointers and the pixel data for the characters from
memory.

For this reason, the VIC uses the mechanism described in section 2.4.3. to
"stun" the processor for 40-43 cycles during the first pixel line of each
text line to read the character pointers. The raster lines in which this
happens are usually called "Bad Lines" ("bad" because they stop the
processor and thus slow down the computer and lead to problems if the
precise timing of a program is essential, e.g. for the transmission of data
to/from a floppy drive).

The character pointer access also happens in the bitmap modes, because the
video matrix data is then used for color information.

Normally, every eighth line inside the display window, starting with the
very first line of the graphics, is a Bad Line, i.e. the first raster line
of each text line. So the position of the Bad Lines depends on the YSCROLL.
As you will see later, the entire graphics display and memory access scheme
depend completely on the position of the Bad Lines.

It is therefore necessary to introduce a more general definition, namely
that of a "Bad Line Condition":

 A Bad Line Condition is given at any arbitrary clock cycle if, at the
 negative edge of ϕ0 at the beginning of the cycle, RASTER >= $30 and RASTER
 <= $f7 and the lower three bits of RASTER are equal to YSCROLL, and if the
 DEN bit was set during an arbitrary cycle of raster line $30.

This definition has to be taken literally. You can produce or cancel a Bad
Line Condition multiple times within an arbitrary raster line in the range
of $30-$f7 by modifying YSCROLL, and thus make every raster line within the
display window completely or partially a Bad Line, or trigger or suppress
all the other functions that are connected with a Bad Line Condition. If
YSCROLL=0, a Bad Line Condition occurs in raster line $30 as soon as the DEN
bit (register $d011, bit 4) is set (for more about the DEN bit, see section
3.10.).

The following three sections describe the function units that are used for
displaying the graphics. Section 3.6. explains the the memory interface used
to read the graphics data and the timing of the accesses within a raster
line. Section 3.7. is about the display unit that converts the text and
bitmap graphics data into colors and generates the addresses for the memory
access. Section 3.8. covers the sprites and their address generation.

3.6. Memory access
------------------

3.6.1. The X coordinates
------------------------

Before explaining the timing of memory accesses within a raster line, we
will quickly explain how to obtain the X coordinates. This is necessary
because the VIC doesn't have a counterpart to the RASTER register that holds
the current X coordinate, so you cannot simply read it with the processor.
But the VIC surely keeps track of the X coordinates internally as the
horizontal sprite positions are based on them, and a pulse at the lightpen
input LP latches the current X position in the register LPX ($d013).

Determining the absolute X coordinates of events within a raster line is not
trivial as you cannot e.g. simply put a sprite to a well-defined X
coordinate and derive from the text characters displayed at the same X
position the X coordinates of the memory accesses belonging to these
characters. The memory access and the display are separate function units
and the read graphics data is not immediately displayed on the screen (there
is in fact a delay of 12 pixels).

So we have taken a different approach: The absolute position of a single X
coordinate within the raster line was measured with the LPX register and the
other X coordinates were determined relative to this. To do that, the IRQ
output of the VIC has been connected to the LP input and the VIC has been
programmed for a raster line interrupt. As the negative edge of IRQ was
defined to be the start of a raster line, the absolute X position of the
line start could be determined in this way. The position of the negative
edge of BA during a Bad Line was also measured with this method and the
result was consistent with the relative distance of IRQ and BA to each
other. Based on these two measurements, the X coordinates of all other
events within a raster line have been determined (see [4]). Only now could
the sprite X coordinates be used to determine the moment of the display
generation of the text characters.

This of course implicitly assumes that the LPX coordinates are the same as
the sprite X coordinates. There is, however, no indication and thus no
reason to suppose that they aren't (a direct correlation would also be the
most simple solution in terms of circuit design).

3.6.2. Access types
-------------------

The VIC generates two kinds of graphics that require access to memory: The
text/bitmap graphics (also often called "background graphics" or simply
"graphics") and the sprite graphics. Both require accesses to two separate
memory areas:

For the text/bitmap graphics:

 · The video matrix, an area of 1000 video addresses (40×25, 12 bits each)
   that can be moved in 1KB steps within the 16KB address space of the VIC
   with the bits VM10-VM13 of register $d018. It stores the character codes
   and their color for the text modes and some of the color information of
   8×8 pixel blocks for the bitmap modes. The Color RAM is part of the video
   matrix and delivers the upper 4 bits of the 12-bit matrix. The data read
   from the video matrix is stored in an internal buffer in the VIC, the
   40×12 bit video matrix/color line.

 · The character generator or, respectively, the bitmap: an area of 2048
   bytes (bitmap: 8000 bytes) that can be moved in 2KB steps (bitmap: 8KB
   steps) within the VIC address space with the bits CB11-CB13 (bitmap: only
   CB13) of register $d018. It stores the pixel data of the characters for
   the text modes and the bitmap for the bitmap modes. The character
   generator is not to be confused with the Char ROM. The Char ROM contains
   prepared bit patterns that can be used as a character generator, but you
   can also put the character generator in normal RAM to define your own
   character images.

For the sprites:

 · The sprite data pointers: 8 bytes after the end of the video matrix,
   that select one out of 256 blocks of 64 bytes within the VIC address
   space for each sprite.

 · The sprite data: an area of 63 bytes containing the pixel data of the
   sprites which can be moved in steps of 64 bytes with the sprite data
   pointers, independently for each sprite.

Corresponding to these memory areas, the VIC performs 4 different kinds of
graphics accesses:

1. To the video matrix ("c-access", 12 bits wide).

2. To the pixel data, i.e. character generator or bitmap ("g-access", 8
   bits wide).

3. To the sprite data pointers ("p-access", 8 bits wide).

4. To the sprite data ("s-access", 8 bits wide).

Moreover, the VIC does two additional types of accesses:

5. Accesses for refreshing the dynamic RAM: 5 read accesses per raster
   line.

6. Idle accesses. As described, the VIC accesses memory in every first clock
   phase although there are some cycles in which no other of the above
   mentioned accesses is pending. In this case, the VIC does an idle access:
   a read access to video address $3fff (i.e. to $3fff, $7fff, $bfff or
   $ffff depending on the VIC bank), the result of which is discarded.

3.6.3. Timing of a raster line
------------------------------

The sequence of VIC memory accesses within a raster line is hard-wired,
independent of the graphics mode and the same for every raster line. The
negative edge of IRQ on a raster interrupt has been used to define the
beginning of a line (this is also the moment in which the RASTER register
is incremented). Raster line 0 is, however, an exception: In this line, IRQ
and incrementing (resp. resetting) of RASTER are performed one cycle later
than in the other lines. But for simplicity we assume equal line lengths
and define the beginning of raster line 0 to be one cycle before the
occurrence of the IRQ.

First the timing diagrams, the explanation will follow below:


6569, Bad Line, no sprites:

Cycl-# 6                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6
       3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 1
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
       __
   IRQ   ________________________________________________________________________________________________________________________________
       ________________________                                                                                      ____________________
    BA                         ______________________________________________________________________________________
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _                                                                                 _ _ _ _ _ _ _ _ _ _
   AEC _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _________________________________________________________________________________ _ _ _ _ _ _ _ _ _

   VIC i 3 i 4 i 5 i 6 i 7 i r r r r rcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcg i i 0 i 1 i 2 i 3
  6510  x x x x x x x x x x x x X X X                                                                                 x x x x x x x x x x

Graph.                      |===========01020304050607080910111213141516171819202122232425262728293031323334353637383940=========

X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
       1111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111
       89999aaaabbbbccccddddeeeeff0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff000011112222333344445555666677778888999
       c048c048c048c048c048c048c04048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048


6569, no Bad Line, no sprites (shortened):

Cycl-# 6                   1 1 1 1 1 1 1 1 1 1 |5 5 5 5 5 5 5 6 6 6 6
       3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |3 4 5 6 7 8 9 0 1 2 3 1
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _
    ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _
       __                                      |
   IRQ   ______________________________________|________________________
       ________________________________________|________________________
    BA                                         |
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _
   AEC _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ 
                                               |
   VIC i 3 i 4 i 5 i 6 i 7 i r r r r r g g g g |g g g i i 0 i 1 i 2 i 3
  6510  x x x x x x x x x x x x x x x x x x x x| x x x x x x x x x x x x
                                               |
Graph.                      |===========0102030|7383940=========
                                               |
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|\\\\\\\\\\\\\\\\\\\\\\\\
       1111111111111111111111111110000000000000|111111111111111111111111
       89999aaaabbbbccccddddeeeeff0000111122223|344445555666677778888999
       c048c048c048c048c048c048c04048c048c048c0|c048c048c048c048c048c048


6567R56A, Bad Line, sprites 5-7 active in this line, sprite 0 in the next
line (shortened):

Cycl-# 6                   1 1 1 1 1 1 1 1 1 1 |5 5 5 5 5 5 5 6 6 6 6 6
       4 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |3 4 5 6 7 8 9 0 1 2 3 4 1
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _ _
    ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ 
       __                                      |
   IRQ   ______________________________________|__________________________
       ____                  __                |    __          __________
    BA     __________________  ________________|____  __________
        _ _ _ _ _             _ _ _ _          |     _ _ _ _     _ _ _ _ _
   AEC _ _ _ _ _ _____________ _ _ _ __________|_____ _ _ _ _____ _ _ _ _ 
                                               |
   VIC i 3 i 4 i 5sss6sss7sssr r r r rcgcgcgcgc|gcgcg i i i 0sss1 i 2 i 3 
  6510  x x X X X             x X X X          |     x X X X     x x x x x
                                               |
Graph.                      |===========0102030|7383940===========
                                               |
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|\\\\\\\\\\\\\\\\\\\\\\\\\\
       1111111111111111111111111110000000000000|11111111111111111111111111
       999aaaabbbbccccddddeeeeffff0000111122223|3444455556666777788889999a
       48c048c048c048c048c048c048c048c048c048c0|c048c048c048c048c048c048c0


6567R8, no Bad Line, sprites 2-7 active in this line, sprites 0-4 in the
next line (shortened):

Cycl-# 6                   1 1 1 1 1 1 1 1 1 1 |5 5 5 5 5 5 5 6 6 6 6 6 6
       5 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |3 4 5 6 7 8 9 0 1 2 3 4 5 1
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _ _ _
    ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ _
       __                                      |
   IRQ   ______________________________________|____________________________
                             __________________|________
    BA ______________________                  |        ____________________
                              _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _
   AEC _______________________ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ ______________
                                               |
   VIC ss3sss4sss5sss6sss7sssr r r r r g g g g |g g g i i i i 0sss1sss2sss3s
  6510                        x x x x x x x x x| x x x x X X X
                                               |
Graph.                      |===========0102030|7383940============
                                               |
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|\\\\\\\\\\\\\\\\\\\\\\\\\\\\
       1111111111111111111111111110000000000000|1111111111111111111111111111
       999aaaabbbbccccddddeeeeffff0000111122223|344445555666677778888889999a
       48c048c048c048c048c048c048c048c048c048c0|c048c048c048c048c04cccc048c0


The line "Cycl-#" shows the number of the clock cycle within the raster
line. The line starts with cycle 1 and consists of 63 cycles on the 6569,
64 cycles on the 6567R56A, and 65 cycles on the 6567R8. The last cycle of
the previous line and the first cycle of the next line have also been
included in the diagrams to make things clearer.

The lines "ϕ0", "IRQ", "BA" and "AEC" reflect the state of the respective
bus signals. ϕ0 is low in the first phase and high in the second phase.

The symbols in the lines "VIC" and "6510" show what kind of access VIC and
6510 do in the corresponding clock phase (for an explanation of the
different access types of the VIC see section 3.6.2.):

  c  Reading the video matrix and Color RAM (c-access)
  g  Reading the character generator or bitmap (g-access)
 0-7 Reading the sprite data pointer for sprite 0-7 (p-access)
  s  Reading the sprite data (s-access)
  r  DRAM refresh
  i  Idle access

  x  Read or write access of the processor
  X  Processor may do write accesses, stops on first read (BA is low and so
     is RDY)

The line "X coo." contains the X coordinates of the beginning of each clock
phase (thus the "\\\" as a reminder) and the line "Graph." is a projection
of the 40 column display window and the border to these coordinates, for
positioning sprites. However, this doesn't correspond to the signal on the
VIC video output. Also the "Graph." line doesn't show when the border unit
generates the border. This happens approx. 8 pixels later than shown in the
"Graph." line.

To time the accesses of the processor within a raster line when programming,
it's best to use the VIC g-accesses for orientation by changing a byte in
graphics memory with the 6510 and watching on the screen for which character
the change is first visible. The write access of the processor must then
have occurred in the clock phase immediately before. Then you can use the
diagrams to determine the clock cycle in which the access took place and
count the other accesses relative to it.

3.7. Text/bitmap display
------------------------

3.7.1. Idle state / display state
---------------------------------

The text/bitmap display logic in the VIC is in one of two states at any
time: the idle state or the display state.

 - In display state, c- and g-accesses take place, with the addresses and
   interpretation of the data depending on the selected display mode.

 - In idle state, only g-accesses occur. The access is always to address
   $3fff ($39ff when the ECM bit in register $d016 is set). The graphics
   are displayed by the sequencer exactly as in display state, but with
   the video matrix data treated as "0" bits.

The transition from idle to display state occurs as soon as there is a Bad
Line Condition (see section 3.5.). The transition from display to idle
state occurs in cycle 58 of a line if the RC (see next section) contains
the value 7 and there is no Bad Line Condition.

As long as register $d011 is not modified in the middle of a frame, the
display logic is in display state within the display window and in idle
state outside of it. If you set a YSCROLL other than 3 in a 25 line display
window and store a value other than zero in $3fff you can see the black
stripes generated by the sequencer in idle state on the upper or lower edge
of the window.

In [4], idle accesses as well as g-accesses in idle state are called "idle
bus cycle", but the two phenomena are not the same. The accesses marked
with "+" in the diagrams of [4] are normal g-accesses. In this article, the
term "idle access" is only used for the accesses marked with "i" in the
diagrams in section 3.6.3., and not for the g-accesses during idle state.

3.7.2. VC and RC
----------------

Probably the most important result of the VIC examinations is the discovery
of the function of the internal registers "VC" and "RC" of the VIC. These
are used to generate the addresses for accessing the video matrix and the
character generator/bitmap.

Strictly speaking there are three registers:

 · "VC" (video counter) is a 10-bit counter that can be loaded with the
   value from VCBASE.
 · "VCBASE" (video counter base) is a 10-bit data register with reset input
   that can be loaded with the value from VC.
 · "RC" (row counter) is a 3-bit counter with reset input.

Apart from these, there is a mechanism in the VIC which keeps track of the
position within the internal 40×12 bit video matrix/color line where read
character pointers are stored or read back from again, respectively. We will
call this the "VMLI" (video matrix line index) here.

On the VIC, the VMLI is actually implemented as a 40-bit shift register
which under normal circumstances shifts along a single "1" bit that
addresses exactly one cell of the video matrix line. To start this sequence
in display state, a new "1" bit is shifted in at the input, and in idle
state the register has run empty. This may be the reason why idle state
graphics (see section 3.7.3.9.) are black - there is no color information
coming in from the video matrix line.

With programming tricks (see section 3.14.6.) is it possible to manipulate
the shift register to contain more than one set bit, causing more than one
memory cell to be addressed at the same time. This usually leads to highly
unstable behavior and mixing of character and color data which varies among
VIC chip revisions and can also depend on factors such as the chip
temperature. As these effects are not of any known practical use on the C64,
we will in the following simplify the description of the VMLI by treating it
as an ordinary 6-bit counter with a reset input.

These four registers behave according to the following rules:

1. Once somewhere outside of the range of raster lines $30-$f7 (i.e.
   outside of the Bad Line range), VCBASE is reset to zero. This is
   presumably done in raster line 0; the exact moment cannot be determined
   and is irrelevant.

2. In the first phase of cycle 14 of each line, VC is loaded from VCBASE
   (VCBASE->VC) and VMLI is cleared. If there is a Bad Line Condition in
   this phase, RC is also reset to zero.

3. If there is a Bad Line Condition in cycles 12-54, BA is set low and the
   c-accesses are started. Once started, one c-access is done in the second
   phase of every clock cycle in the range 15-54. The read data is stored in
   the video matrix/color line at the position specified by VMLI. This data
   is then also internally read from the position specified by VMLI on each
   g-access in display state.

4. VC and VMLI are incremented after each g-access in display state.

5. In the first phase of cycle 58, the VIC checks if RC=7. If so, the video
   logic goes to idle state and VCBASE is loaded from VC (VC->VCBASE). If
   the video logic is still in display state (which is always the case if
   there is a Bad Line Condition), then RC is incremented.

These rules normally make VC count all 1000 addresses of the video matrix
within the display frame, and RC count the 8 pixel lines of each text line.
But this behavior of VC and RC is largely determined by Bad Line Conditions
which you can affect with the processor via YSCROLL, giving you more control
over VC and RC within certain limits.

3.7.3 Graphics modes
--------------------

The graphics data sequencer provides eight different graphics modes that are
selected by the bits ECM (Extended Color Mode), BMM (Bit Map Mode) and MCM
(Multi Color Mode) in the registers $d011 and $d016. Of the eight possible
bit combinations, three are "invalid" and generate the same output: the
color black. The idle state is a bit special in that no c-accesses occur in
it and the sequencer uses "0" bits for the video matrix data.

The sequencer outputs the graphics data in every raster line in the area of
the display column as long as the vertical border flip-flop is reset (see
section 3.9.). Outside of the display column and if the flip-flop is set,
the last current background color is displayed (this area is normally
covered by the border). The heart of the sequencer is an 8-bit shift
register that is shifted by 1 bit for every pixel, and reloaded with new
graphics data after each g-access. With XSCROLL from register $d016 the
reloading can be delayed by 0-7 pixels, thus shifting the display up to 7
pixels to the right. If XSCROLL is increased in the middle of a line, the
sequencer produces additional background color pixels. If it is decreased,
the display of the next set of 8 pixels starts early, aborting the currently
displayed character.

The address generator for the text/bitmap accesses (c- and g-accesses)
basically has three modes for the g-accesses, while the c-accesses always
follow the same address scheme. In display state, the BMM bit selects either
character generator accesses (BMM=0) or bitmap accesses (BMM=1). In idle
state, the g-accesses are always done at video address $3fff. If the ECM bit
is set, the address generator always holds the address lines 9 and 10 low
without any other changes to the addressing scheme (e.g. the g-accesses in
idle state then occur at address $39ff).

In the next sections we will cover the eight graphics modes separately, and
describe the generated addresses and the interpretation of the read data on
c- and g-accesses. This is followed by a description of the peculiarities of
the idle state. For easy reference, the addresses are always given
explicitly for each mode although, for example, the c-accesses are always
identical.

3.7.3.1. Standard text mode (ECM/BMM/MCM=0/0/0)
-----------------------------------------------

In this mode (as in all text modes), the VIC reads 8-bit character pointers
from the video matrix that specify the address of the dot matrix of the
character within the character generator. A character set of 256 characters
is available, each consisting of 8×8 pixels which are stored in 8 successive
bytes in the character generator. Both video matrix and character generator
can be moved in memory with the bits VM10-VM13 and CB11-CB13 of register
$d018.

In standard text mode, each bit in the character generator directly
corresponds to one pixel on the screen. The foreground color is given by the
color nybble from the video matrix for each character, the background color
is set globally with register $d021.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |      Color of     | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
 |     "1" pixels    |    |    |    |    |    |    |    |    |
 +-------------------+----+----+----+----+----+----+----+----+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13|CB12|CB11| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       |
 | "0": Background color 0 ($d021)       |
 | "1": Color from bits 8-11 of c-data   |
 +---------------------------------------+

3.7.3.2. Multicolor text mode (ECM/BMM/MCM=0/0/1)
-------------------------------------------------

This mode allows displaying four-colored characters at the expense of
horizontal resolution. If bit 11 of the c-data is zero, the character is
displayed as in standard text mode with only the colors 0-7 available for
the foreground. If bit 11 is set, two adjacent bits each of the dot matrix
form one pixel. In this way, the resolution of a character is effectively
reduced to 4×8 pixels, with each pixel being twice as wide so the total
width of the characters remains the same.

It is interesting to note that not only the bit combination "00" but also
"01" is regarded as "background" for the purposes of sprite priority and
collision detection.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 | MC |   Color of   | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
 |flag|  "11" pixels |    |    |    |    |    |    |    |    |
 +----+--------------+----+----+----+----+----+----+----+----+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13|CB12|CB11| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       | MC flag = 0
 | "0": Background color 0 ($d021)       |
 | "1": Color from bits 8-10 of c-data   |
 +---------------------------------------+
 |         4 pixels (2 bits/pixel)       |
 |                                       |
 | "00": Background color 0 ($d021)      | MC flag = 1
 | "01": Background color 1 ($d022)      |
 | "10": Background color 2 ($d023)      |
 | "11": Color from bits 8-10 of c-data  |
 +---------------------------------------+

3.7.3.3. Standard bitmap mode (ECM/BMM/MCM=0/1/0)
-------------------------------------------------

In this mode, the VIC reads the graphics data from a 320×200 pixel bitmap in
which each bit corresponds to one pixel on the screen. The data from the
video matrix is used for color information. As the video matrix is still
only a 40×25 matrix, you can only specify the colors for blocks of 8×8
pixels individually (sort of a YC 8:1 format). As the designers of the VIC
wanted to realize the bitmap mode with as little additional circuitry as
possible (the VIC-I didn't have a bitmap mode), the arrangement of the
bitmap in memory is somewhat weird: In contrast to modern video chips that
read the bitmap in a linear fashion from memory, the VIC forms an 8×8 pixel
block on the screen from 8 successive bytes of the bitmap. The video matrix
and the bitmap can be moved in memory with the bits VM10-VM13 and CB13 of
register $d018.

In standard bitmap mode, each bit in the bitmap directly corresponds to one
pixel on the screen. Foreground and background color can be arbitrarily set
for each 8×8 pixel block.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |       unused      |     Color of      |     Color of      |
 |                   |    "1" pixels     |    "0" pixels     |
 +-------------------+-------------------+-------------------+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       |
 | "0": Color from bits 0-3 of c-data    |
 | "1": Color from bits 4-7 of c-data    |
 +---------------------------------------+

3.7.3.4. Multicolor bitmap mode (ECM/BMM/MCM=0/1/1)
---------------------------------------------------

Similar to the multicolor text mode, this mode also forms (twice as wide)
pixels by combining two adjacent bits each. So the resolution is reduced to
160×200 pixels.

The bit combination "01" is also treated as "background" for the sprite
priority and collision detection, as in multicolor text mode.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |     Color of      |     Color of      |     Color of      |
 |    "11 pixels"    |    "01" pixels    |    "10" pixels    |
 +-------------------+-------------------+-------------------+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         4 pixels (2 bits/pixel)       |
 |                                       |
 | "00": Background color 0 ($d021)      |
 | "01": Color from bits 4-7 of c-data   |
 | "10": Color from bits 0-3 of c-data   |
 | "11": Color from bits 8-11 of c-data  |
 +---------------------------------------+

3.7.3.5. ECM text mode (ECM/BMM/MCM=1/0/0)
------------------------------------------

This text mode is the same as the standard text mode, but it allows the
selection of one of four background colors for every single character. The
selection is made with the upper two bits of the character pointer. This,
however, reduces the available character set from 256 to 64 characters.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |     Color of      |Back.col.| D5 | D4 | D3 | D2 | D1 | D0 |
 |    "1" pixels     |selection|    |    |    |    |    |    |
 +-------------------+---------+----+----+----+----+----+----+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13|CB12|CB11|  0 |  0 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       |
 | "0": Depending on bits 6/7 of c-data  |
 |      00: Background color 0 ($d021)   |
 |      01: Background color 1 ($d022)   |
 |      10: Background color 2 ($d023)   |
 |      11: Background color 3 ($d024)   |
 | "1": Color from bits 8-11 of c-data   |
 +---------------------------------------+

3.7.3.6. Invalid text mode (ECM/BMM/MCM=1/0/1)
----------------------------------------------

Setting the ECM and MCM bits simultaneously doesn't select one of the
"official" graphics modes of the VIC but creates only black pixels.
Nevertheless, the graphics data sequencer internally generates valid
graphics data that can trigger sprite collisions even in this mode. By using
sprite collisions you can also read out the generated data (but you cannot
see anything; the screen is black). You can, however, only distinguish
foreground and background pixels as you cannot get color information from
sprite collisions.

The generated graphics is similar to that of the multicolor text mode, but
the character set is limited to 64 characters as in ECM mode.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 | MC |         unused         | D5 | D4 | D3 | D2 | D1 | D0 |
 |flag|                        |    |    |    |    |    |    |
 +----+------------------------+----+----+----+----+----+----+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13|CB12|CB11|  0 |  0 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       | MC flag = 0
 | "0": Black (background)               |
 | "1": Black (foreground)               |
 +---------------------------------------+
 |         4 pixels (2 bits/pixel)       |
 |                                       |
 | "00": Black (background)              | MC flag = 1
 | "01": Black (background)              |
 | "10": Black (foreground)              |
 | "11": Black (foreground)              |
 +---------------------------------------+

3.7.3.7. Invalid bitmap mode 1 (ECM/BMM/MCM=1/1/0)
--------------------------------------------------

This mode also only displays a black screen, but the pixels can still be
read out with the sprite collision trick.

The structure of the graphics is basically as in standard bitmap mode, but
the bits 9 and 10 of the g-addresses are always zero due to the set ECM bit
and so the graphics are, roughly said, made up of four "sections" each of
which is repeated four times.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |                           unused                          |
 +-----------------------------------------------------------+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13| VC9| VC8|  0 |  0 | VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       |
 | "0": Black (background)               |
 | "1": Black (foreground)               |
 +---------------------------------------+

3.7.3.8. Invalid bitmap mode 2 (ECM/BMM/MCM=1/1/1)
--------------------------------------------------

The last invalid mode also creates a black screen that can be "scanned" with
sprite-graphics collisions.

The structure of the graphics is basically as in multicolor bitmap mode, but
the bits 9 and 10 of the g-addresses are always zero due to the set ECM bit,
with the same results as in the first invalid bitmap mode. As usual, the bit
combination "01" is part of the background.

c-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |                           unused                          |
 +-----------------------------------------------------------+

g-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |CB13| VC9| VC8|  0 |  0 | VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         4 pixels (2 bits/pixel)       |
 |                                       |
 | "00": Black (background)              |
 | "01": Black (background)              |
 | "10": Black (foreground)              |
 | "11": Black (foreground)              |
 +---------------------------------------+

3.7.3.9. Idle state
-------------------

In idle state, the VIC reads the graphics data from address $3fff ($39ff if
the ECM bit is set) and displays it in the selected graphics mode, but with
the video matrix data, normally read in the c-accesses, being all "0" bits.
So the byte at address $3fff/$39ff is output repeatedly.

c-access

 No c-accesses occur.

 Data

 +----+----+----+----+----+----+----+----+----+----+----+----+
 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+
 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+

g-access

 Addresses (ECM=0)

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Addresses (ECM=1)

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |  1 |  1 |  1 |  0 |  0 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  1 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        | Standard text mode/
 |                                       | Multicolor text mode/
 | "0": Background color 0 ($d021)       | ECM text mode
 | "1": Black                            |
 +---------------------------------------+
 |         8 pixels (1 bit/pixel)        | Standard bitmap mode/
 |                                       | Invalid text mode/
 | "0": Black (background)               | Invalid bitmap mode 1
 | "1": Black (foreground)               |
 +---------------------------------------+
 |         4 pixels (2 bits/pixel)       | Multicolor bitmap mode
 |                                       |
 | "00": Background color 0 ($d021)      |
 | "01": Black (background)              |
 | "10": Black (foreground)              |
 | "11": Black (foreground)              |
 +---------------------------------------+
 |         4 pixels (2 bits/pixel)       | Invalid bitmap mode 2
 |                                       |
 | "00": Black (background)              |
 | "01": Black (background)              |
 | "10": Black (foreground)              |
 | "11": Black (foreground)              |
 +---------------------------------------+

3.8. Sprites
------------

Apart from the text/bitmap graphics, the VIC can display eight independent,
24×21 pixels large, freely movable objects, the "sprites" (called "MOBs"
(Movable Object Blocks) in [2]).

The sprites can have arbitrary positions on the screen, you can switch each
of them on and off with the bits of register $d015 (MxE), expand them by the
factor 2 in X and/or Y direction with registers $d017/$d01d (with their
resolution still being 24×21 pixels), choose between standard and multicolor
mode with register $d01c (MxMC), set the display priority with respect to
the text/bitmap graphics with register $d01b (MxDP) and assign a different
color to each sprite (registers $d027-$d02e). The VIC also has the ability
to detect collisions between sprites among themselves or between sprites and
text/bitmap graphics, and to trigger an interrupt on such collisions (see
section 3.12.).

The position of the top left corner of a sprite is specified via its
respective coordinate registers (MxX, MxY). There are 8 bits for the Y
coordinate and 9 bits for the X coordinate (the most significant bits of the
X coordinates of all sprites are collected in register $d010).

3.8.1. Memory access and display
--------------------------------

The 63 bytes of sprite data necessary for displaying 24×21 pixels are
stored in memory in a linear fashion: 3 adjacent bytes form one line of the
sprite.

The start of the data block of each sprite can be chosen in steps of 64
bytes within the 16KB address space of the VIC. For this, the VIC reads a
sprite data pointer for each sprite in every raster line from the very last
8 bytes of the video matrix (p-access) that is then used as the upper 8 bits
of the address for sprite data accesses (s-accesses). The lower 6 bits come
from a sprite data counter (MC0-MC7, one for each sprite) that plays a
similar role for the sprites as VC does for the video matrix. As the
p-accesses are performed in every raster line you can change the appearance
of a sprite in the middle of its display by changing the sprite data
pointer.

When s-accesses are necessary for a sprite, they are performed in the three
half-cycles directly after the sprite's p-access. The VIC also uses the BA
and AEC signals (as for the Bad Lines) to access the bus in the second clock
phase. BA will also go low three cycles before the proper access in this
case. The s-accesses are done in every raster line in which the sprite is
visible (for the sprites 0-2, this always happens the line before, see the
timing diagrams in section 3.6.3.).

Like the text and bitmap graphics, the sprites also have a standard mode and
a multicolor mode. In standard mode, every bit directly corresponds to one
pixel on the screen. A "0" pixel is transparent and the underlying graphics
are visible below it, a "1" pixel is displayed in the respective sprite
color defined by registers $d027-$d02e. In multicolor mode, two adjacent
bits each form one pixel, thus reducing the resolution of the sprite to
12×21 pixels, with the pixels being twice as wide.

Moreover, the sprites can be doubled in their size on the screen in X and/or
Y direction (X/Y expansion). The sprite resolution doesn't change but each
sprite pixel simply becomes twice as wide or tall. So a pixel of an
x-expanded multicolor sprite is four times as wide as a pixel of an
unexpanded standard-mode sprite. Although both expansions look similar, they
are implemented completely differently in the VIC. The X expansion simply
instructs the sprite data sequencer to output pixels at half frequency. But
the Y expansion makes the sprite address generator read from the same
addresses two lines in succession so that every sprite line is output twice.

Each sprite has its own sprite data sequencer whose core is a 24-bit shift
register. Apart from that, there are two internal registers for every
sprite:

 · "MC" (MOB Data Counter) is a 6-bit counter that can be loaded from
   MCBASE.
 · "MCBASE" (MOB Data Counter Base) is a 6-bit register that can be loaded
   from MC or reset to zero.

Apart from these, there is one “advance line” flip-flop per sprite that
is used to control the Y expansion.

The display of a sprite is handled according to the following rules (the
cycle numbers are only valid for the 6569):

1. The advance line flip-flop is set as long as the corresponding MxYE bit
   in register $d017 is cleared.

2. In the first phases of cycle 55 and 56, the VIC checks for every sprite
   if the corresponding MxE bit in register $d015 is set and the Y
   coordinate of the sprite (odd registers $d001-$d00f) matches the lower 8
   bits of RASTER. If this is the case and the DMA for the sprite is still
   off, the DMA is switched on, MCBASE is cleared, and the advance line
   flip-flop is set.

3. If the MxYE bit of a sprite is set in the second phase of cycle 56 and
   the DMA for that sprite is on, then the advance line flip-flop is
   inverted.

4. In the first phase of cycle 58, the MC of every sprite is loaded from
   its corresponding MCBASE (MCBASE->MC) and the VIC checks if the DMA for
   the sprite is turned on and the Y coordinate of the sprite matches the
   lower 8 bits of RASTER. If this is the case, the display of the sprite is
   turned on. Otherwise, if the DMA for the sprite is turned off, then its
   display is also turned off.

5. If the DMA for a sprite is turned on, three s-accesses are performed in
   sequence in the corresponding cycles assigned to the sprite (see the
   diagrams in section 3.6.3.). The p-accesses are always done, even if the
   sprite is turned off. The read data of the first access is stored in the
   upper 8 bits of the shift register, that of the second one in the middle
   8 bits and that of the third one in the lower 8 bits. MC is incremented
   by one after each s-access.

6. If the sprite display for a sprite is turned on, the shift register is
   shifted left by one bit with every pixel as soon as the current X
   coordinate of the raster beam has matched the X coordinate of the sprite
   (even registers $d000-$d00e), and the bits that are shifted out are
   displayed. If the MxXE bit belonging to the sprite in register $d01d is
   set, the register is only shifted every second pixel and the sprite thus
   appears twice as wide. If the sprite is in multicolor mode, two adjacent
   bits each form one pixel.

7. In the first phase of cycle 16, the VIC checks for each sprite if its
   advance line flip-flop is set. If so, MCBASE is loaded from its
   corresponding MC (MC->MCBASE), thus advancing the sprite display to the
   next line. After that, the VIC checks if MCBASE is equal to 63 and turns
   off the DMA of the sprite if this is the case.

7a. As a special case, if the CPU has cleared one of the MxYE bits in cycle
    15 and the advance line flip-flop of the corresponding sprite was not
    set, then the flip-flop is set and in the next cycle (16) the VIC sets
    MCBASE not to MC but to:
      MCBASE = ((101010 & (MCBASE & MC)) | (010101 & (MCBASE | MC))

As the test in rule 2 is performed at the end of a raster line, the sprite Y
coordinates stored in the registers must be 1 less than the desired Y
position of the first sprite line, as the sprite display will not start
before the following line, after the first sprite data has been read (as
long as the sprite is not positioned to the right of sprite X coordinate
$164 (cycle 58, see rule 4)).

Sprites can be "reused" vertically: If you change the Y coordinate of a
sprite to a later raster line during or after its display has completed, so
that the comparisons mentioned in rules 1 and 2 will match again, the sprite
is displayed again at that Y coordinate (you may then of course also set a
new X coordinate and sprite data pointer). It is therefore possible to
display more than 8 sprites on the screen, which is usually referred to as
"sprite multiplexing" and is an official design feature of the VIC.

This is not possible in the horizontal direction. After 24 displayed pixels,
the shift register has run empty and even if you change the X coordinate
within a line so that the comparison in rule 6 will match again, no sprite
data is displayed any more. So you can only display up to 8 sprites within
one raster line at a time. Also note that on a 6569, sprites with an X
position in the range $1f8-$1ff become invisible because these values are
never reached by the X raster counter; to place a sprite one pixel to the
left of X position 0 it has to be at X position $1f7.

Here is an overview of the scheme of p- and s-accesses:

p-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |VM13|VM12|VM11|VM10|  1 |  1 |  1 |  1 |  1 |  1 |  1 |Sprite number |
 +----+----+----+----+----+----+----+----+----+----+----+--------------+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 | MP7| MP6| MP5| MP4| MP3| MP2| MP1| MP0|
 +----+----+----+----+----+----+----+----+

s-access

 Addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | MP7| MP6| MP5| MP4| MP3| MP2| MP1| MP0| MC5| MC4| MC3| MC2| MC1| MC0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

 Data

 +----+----+----+----+----+----+----+----+
 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+
 |         8 pixels (1 bit/pixel)        |
 |                                       | MxMC = 0
 | "0": Transparent                      |
 | "1": Sprite color ($d027-$d02e)       |
 +---------------------------------------+
 |         4 pixels (2 bits/pixel)       |
 |                                       |
 | "00": Transparent                     | MxMC = 1
 | "01": Sprite multicolor 0 ($d025)     |
 | "10": Sprite color ($d027-$d02e)      |
 | "11": Sprite multicolor 1 ($d026)     |
 +---------------------------------------+

3.8.2. Priority and collision detection
---------------------------------------

As soon as several graphics elements (sprites and text/bitmap graphics)
overlap on the screen, the VIC has to decide which element shall be
displayed in the foreground [7]. To do this, every element has an assigned
priority, and only the element with highest priority is displayed.

The sprites have a fixed hierarchy among themselves: Sprite 0 has the
highest and sprite 7 the lowest priority. If two sprites overlap, the sprite
with the higher number is displayed only where the other sprite has a
transparent pixel.

The priority of the sprites to the text/bitmap graphics can be controlled
within some limits. First of all, the text/bitmap graphics are divided into
foreground pixels and background pixels. Which bit combinations belong to
the foreground or background is decided by the MCM bit in register $d016,
independently of the state of the graphics data sequencer and of the BMM and
ECM bits in register $d011:

             | MCM=0 |   MCM=1
 ------------+-------+-----------
 Bits/pixel  |   1   |     2
 Pixels/byte |   8   |     4
 Background  |  "0"  | "00", "01"
 Foreground  |  "1"  | "10", "11"

In multicolor mode (MCM=1), the bit combinations "00" and "01" belong to the
background and "10" and "11" to the foreground, whereas in standard mode
(MCM=0), "0" pixels belong to the background and "1" pixels to the
foreground. It should be noted that this is also valid for the graphics
generated in idle state.

Of course, graphics elements with lower priority than any overlaid sprites
are visible where all the sprites have transparent pixels.

With the MxDP bits from register $d01b, you can separately specify for each
sprite whether it shall be displayed in front of or behind the foreground
pixels (the table in [2] is wrong):

 MxDP=0:

       +-----------------------+
       |  Background graphics  |  low priority
     +-----------------------+ |
     |  Foreground graphics  |-+
   +-----------------------+ |
   |       Sprite x        |-+
 +-----------------------+ |
 |     Screen border     |-+
 |                       |   high priority
 +-----------------------+

 MxDP=1:

       +-----------------------+
       |  Background graphics  |  low priority
     +-----------------------+ |
     |       Sprite x        |-+
   +-----------------------+ |
   |  Foreground graphics  |-+
 +-----------------------+ |
 |     Screen border     |-+
 |                       |   high priority
 +-----------------------+

In the latter case, those foreground graphics pixels which overlap
non-transparent sprite pixels "inherit" the priority of the sprite. For
example, if sprite 0 is set to appear behind the foreground (M0DP=1) then
the foreground pixels which overlap the image of sprite always stay visible,
even if sprite 0 overlaps with lower-priority sprites which are configured
to appear in front of the foreground (MxDP=0).

This behavior is hard to represent consistently in a simple picture of
stacked graphics layers:

           +-----------------------+
           |  Background graphics  |  low priority
         +-----------------------+ |
         |  Foreground graphics  |-+
         |    visible through    |
         |    sprites 1 and 0    |
       +-----------------------+ |
       |       Sprite 1        |-+
     +-----------------------+ |
     |       Sprite 0        |-+
   +-----------------------+ |
   |  Foreground graphics  |-+
   |  in front of sprite 0 |
 +-----------------------+ |
 |     Screen border     |-+
 |                       |   high priority
 +-----------------------+

One way to think about this is to imagine the foreground pixels which
overlay a sprite becoming "baked into" the sprite image itself and be
handled with the sprite's priority from then on.

If you choose one of the invalid video modes only the sprites will be
visible (fore- and background graphics will all become black, see sections
3.7.3.6.-3.7.3.8.), but by setting the sprites to appear behind the
foreground graphics, the foreground graphics will actually become visible as
black pixels overlaying the sprite image.

In addition to the priority management, the VIC has the ability to detect
collisions of sprites among themselves and of sprites and foreground pixels
of the text/bitmap graphics.

A collision of sprites among themselves is detected as soon as two or more
sprite data sequencers output a non-transparent pixel in the course of
display generation (this can also happen somewhere outside of the visible
screen area). In this case, the MxM bits of any affected sprites are set in
register $d01e and (if allowed, see section 3.12.), an interrupt is
generated. The bits remain set until the register is read by the processor
and are cleared automatically by the read access.

A collision of sprites and other graphics data is detected as soon as one
or more sprite data sequencers output a non-transparent pixel and the
graphics data sequencer outputs a foreground pixel in the course of display
generation. In this case, the MxD bits of the affected sprites are set in
register $d01f and (if allowed, see section 3.12.), an interrupt is
generated. As with the sprite-sprite collision, the bits remain set until
the register is read by the processor.

If the vertical border flip-flop is set (normally within the upper/lower
border, see next section), the output of the graphics data sequencer is
turned off and there are no collisions of sprites with graphics data.

3.9. The border unit
--------------------

The VIC uses two flip-flops to generate the border around the display
window: A main border flip-flop and a vertical border flip-flop.

The main border flip-flop controls the border display. If it is set, the VIC
displays the color stored in register $d020, otherwise it displays the color
that the priority multiplexer switches through from the graphics or sprite
data sequencer. So the border overlays the text/bitmap graphics as well as
the sprites. It has the highest display priority.

The vertical border flip-flop is for auxiliary control of the upper/lower
border. If it is set, the main border flip-flop cannot be reset. Apart from
that, the vertical border flip-flop controls the output of the graphics data
sequencer. The sequencer only outputs data if the flip-flop is not set,
otherwise it displays the background color. This was probably done to
prevent sprite-graphics collisions in the border area.

There are 2×2 comparators belonging to each of the two flip-flops. These
comparators compare the X/Y position of the raster beam with one of two
hardwired values, depending on the state of the CSEL and RSEL bits, to
control the flip-flops. The comparisons only match if the values are reached
precisely. There is no comparison with an interval.

The horizontal comparison values are:

       |   CSEL=0   |   CSEL=1
 ------+------------+-----------
 Left  |  31 ($1f)  |  24 ($18)
 Right | 335 ($14f) | 344 ($158)

And the vertical ones are:

        |   RSEL=0  |  RSEL=1
 -------+-----------+----------
 Top    |  55 ($37) |  51 ($33)
 Bottom | 247 ($f7) | 251 ($fb)

The flip-flops are switched according to the following rules:

1. When the X coordinate reaches the right comparison value, the main border
   flip-flop is set.

2. When the Y coordinate reaches the bottom comparison value in cycle 63,
   the vertical border flip-flop is set.

3. When the Y coordinate reaches the top comparison value in cycle 63 and
   the DEN bit in register $d011 is set, the vertical border flip-flop is
   reset.

4. When the X coordinate reaches the left comparison value and the Y
   coordinate reaches the bottom one, the vertical border flip-flop is set.

5. When the X coordinate reaches the left comparison value and the Y
   coordinate reaches the top one and the DEN bit in register $d011 is set,
   the vertical border flip-flop is reset.

6. When the X coordinate reaches the left comparison value and the vertical
   border flip-flop is not set, the main flip-flop is reset.

So the Y coordinate is checked once or twice within each raster line: In
cycle 63 and when the X coordinate reaches the left comparison value.

By appropriate switching of the CSEL/RSEL bits you can prevent the
comparison values from being reached and thus turn off the border partly or
completely (see 3.14.1.).

3.10. Display Enable
--------------------

The DEN bit (Display Enable, register $d011, bit 4) allows switching the
text/bitmap graphics on or off. It is normally set. The bit affects two
functions of the VIC: The Bad Lines and the vertical border unit.

 - A Bad Line Condition can only occur if the DEN bit has been set for at
   least one cycle somewhere in raster line $30 (see section 3.5.).
 - If the DEN bit is cleared, the reset input of the vertical border
   flip-flop is deactivated (see section 3.9.). Thus the upper/lower border
   will never be turned off.

So clearing the DEN bit will normally prevent Bad Lines (and thus c- and
g-accesses) from ever occurring and make the whole screen display the border
color.

3.11. Lightpen
--------------

On a negative edge of the LP input, the current position of the raster beam
is latched in the registers LPX ($d013) and LPY ($d014). LPX contains the
upper 8 bits (of 9) of the X position and LPY the lower 8 bits (likewise of
9) of the Y position. So the horizontal resolution of the light pen is
limited to 2 pixels.

Only one negative edge on LP is recognized per frame. If multiple edges
occur on LP, all following ones are ignored. The trigger is not released
until the start of the next frame.

As the LP input of the VIC is connected to the keyboard matrix, like the
lines of the joystick ports, it can also be controlled by software. This is
done via bit 4 of port B of CIA A ($dc01/$dc03). This allows determining the
current X position of the raster beam by triggering an LP edge and reading
from LPX afterwards (the VIC has no register that would allow reading the X
position directly). This can, for example, be used for cycle-exact
synchronization of raster interrupt routines.

The values you get from the LPX register can be calculated from the sprite
coordinates of the timing diagrams in section 3.6.3. The reference point is
the end of the cycle in which the LP line is triggered. For example, if you
trigger LP in cycle 20, you get the value $1e in LPX, corresponding to the
sprite coordinate $03c (LPX contains the upper 8 bits of the 9 bit X
coordinate).

The VIC is also able to trigger an interrupt on a negative edge of the LP
pin (see next section), likewise only once per frame.

3.12. VIC interrupts
--------------------

The VIC has the possibility to generate interrupts for the processor when
certain events occur. For this purpose, the IRQ output of the VIC is
connected to the IRQ input of the 6510. The VIC interrupts are therefore
maskable with the I flag in the processor status register.

There are four interrupt sources in the VIC. Each source has a corresponding
bit in the interrupt latch (register $d019) and a bit in the interrupt
enable register ($d01a). When an interrupts occurs, the corresponding bit in
the latch is set. To clear it, the processor has to write a "1" there "by
hand". The VIC doesn't clear the latch on its own.

If at least one latch bit and the corresponding bit in the enable register
is set, the VIC holds the IRQ line low and thereby triggers an interrupt in
the processor. So the four interrupt sources can be independently enabled
and disabled using the enable bits. Since the VIC, as mentioned, doesn't
clear the interrupt latch by itself, the processor has to do this before it
resets the I flag or returns from the interrupt routine. Otherwise the
interrupt will be re-triggered immediately (the IRQ input of the 6510 is
state-sensitive).

The following table describes the four interrupt sources and their bits in
the latch and enable registers:

 Bit|Name| Trigger condition
 ---+----+-----------------------------------------------------------------
  0 | RST| Reaching a certain raster line. The line is specified by writing
    |    | to register $d012 and bit 7 of $d011, and internally stored by
    |    | the VIC for the raster compare. The test for reaching the
    |    | interrupt raster line is done in cycle 1 of every line (for line
    |    | 0, in cycle 2). It is possible to trigger an interrupt
    |    | immediately by writing to $d011/$d012, but the interrupt can
    |    | never occur more than once per raster line.
  1 | MBC| Collision of at least one sprite with the text/bitmap graphics
    |    | (one sprite data sequencer outputs non-transparent pixel at the
    |    | same time at which the graphics data sequencer outputs a
    |    | foreground pixel)
  2 | MMC| Collision of two or more sprites (two sprite data sequencers
    |    | output a non-transparent pixel at the same time)
  3 | LP | Negative edge on the LP input (lightpen)

For the MBC and MMC interrupts, only the first collision will trigger an
interrupt (i.e. if the collision registers $d01e or $d01f contained the
value zero before the collision). To trigger further interrupts after a
collision, the respective register has to be cleared first by reading from
it.

The bit 7 in the latch $d019 reflects the inverted state of the IRQ output
of the VIC.

3.13. DRAM refresh
------------------

The VIC performs five read accesses in every raster line for refreshing the
dynamic RAM. An 8-bit refresh counter (REF) is used to generate 256 DRAM row
addresses. The counter is reset to $ff in raster line 0 and decremented by 1
after each refresh access. When the counter underflows, it wraps back to
$ff.

So the VIC will access addresses $3fff, $3ffe, $3ffd, $3ffc and $3ffb in
line 0, addresses $3ffa, $3ff9, $3ff8, $3ff7 and $3ff6 in line 1 etc.

 Refresh addresses

 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0 |
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 |  1 |  1 |  1 |  1 |  1 |  1 |REF7|REF6|REF5|REF4|REF3|REF2|REF1|REF0|
 +----+----+----+----+----+----+----+----+----+----+----+----+----+----+

3.14. Effects and applications
------------------------------

The following sections will describe some graphical effects that can be
achieved by applying the rules and mechanisms of the VIC described in the
previous sections.

3.14.1. Hyperscreen
-------------------

As explained in section 3.9. the VIC generates the screen border by
comparing the beam coordinates with start and stop positions selected by the
CSEL/RSEL bits. This basically means that the border is not necessarily
displayed within a certain range of coordinates, but rather turned on and
off at certain coordinates. If you now make sure by appropriately switching
CSEL/RSEL that the coordinate comparison never matches, the border may for
example never turn on, allowing graphics in the border area to become
visible that would normally be covered. The technique is called
"hyperscreen" or "opening the border".

However, the graphics that can be displayed in the border area is mainly
limited to sprites, since the graphics data sequencer is in idle state in
this area as no Bad Lines can occur outside of Y coordinates $30-$f7 (see
section 3.5.). But you can still make use of the graphics generated in idle
state.

To turn off the upper/lower border, you proceed as follows:

1. Somewhere in the upper part of the screen, switch to 25-line-border by
   setting the RSEL bit.

2. Now wait until RASTER has reached a value in the range of 248-250. The
   vertical border flip-flop is still cleared as the comparison value for
   RSEL=1 is raster line 251.

3. Then clear the RSEL bit. The comparator is switched and now sets the
   vertical flip-flop at line 247. But this line has already passed and thus
   the VIC "forgets" to turn on the vertical border.

4. After raster line 251, set the RSEL bit again and repeat from step 2.

If you open the upper/lower border with this method, the left/right border
still remains active in the "opened up" area. If you switch from RSEL=0 to
RSEL=1 in the raster line range 52-54, the border never turns off and covers
the whole screen (similar to when the DEN bit is cleared, but Bad Lines
still occur). This is interesting but not very useful.

The left/right border can be turned off with the CSEL bit in a similar way.
However, the timing is much more critical here. Whereas for the vertical
border, you have 4 raster lines for the switch, for the horizontal border
the change from CSEL=1 to CSEL=0 has to be exactly in cycle 56. Likewise,
the horizontal border can be prevented from turning off by switching from
CSEL=0 to CSEL=1 in cycle 17.

If you want to open the left/right border in the upper/lower border area,
you must either start before the vertical border flip-flop is set (i.e.
outside of the upper/lower border), or also open the upper/lower border.
This is because the main border flip-flop can only be reset if the vertical
flip-flop is not set. If you compare both methods, you can verify that the
vertical flip-flop also controls the graphics data sequencer output: With
the first method, only the background color is visible in the opened up
upper/lower border area, whereas the second method displays the idle state
graphics there.

3.14.2. FLD
-----------

When building the graphics out of text lines, the VIC is directed
exclusively by the occurrence of Bad Lines: A Bad Line gives the "start
signal" for the display of one text line. By appropriately changing YSCROLL
(in register $d011) you can suppress and arbitrarily delay the Bad Line
Condition (see 3.5.). In this way you can exactly control in which raster
lines Bad Lines should occur and thus from which raster lines the VIC should
start to display one text line. The distance between two text lines can be
arbitrarily increased if you hold back the next Bad Line long enough. This
effect is called "Flexible Line Distance" (FLD).

For example, if you only allow three Bad Lines on the screen at raster lines
$50, $78 and $a0, the VIC will also only display three text lines at these
positions. The sequencer is in idle state in the lines between.

If you only delay the occurrence of the first Bad Line, you can scroll down
the entire graphics display by large distances without moving a single byte
in display memory.

3.14.3. FLI
-----------

Instead of delaying the occurrence of Bad Lines as for the FLD effect, you
can also artificially create an additional Bad Line before the VIC has
completed the current text line. This is especially interesting for the
bitmap modes, as these use the data from the video matrix (which is read in
the Bad Lines) for color information, so normally only 8×8 pixel blocks each
can be colored individually in bitmap modes. But if you make every raster
line a Bad Line by appropriately modifying YSCROLL, then the VIC will read
from the video matrix in every line and so it will also read new color
information for each line.

This way, each of the 4×8 pixels of a block in multicolor mode can have a
different color. This software-generated new graphics mode is called
"Flexible Line Interpretation" (FLI) and is probably the most outstanding
example of "unconventional" VIC programming.

There is however one problem: If you create a new Bad Line before the
current text line has been finished, VCBASE is not incremented (see section
3.7.2.). The VIC therefore reads from the same addresses of the video matrix
as in the previous line. Since you cannot change the video matrix fast
enough from the processor, you have to switch the base address of the video
matrix with the bits VM10-VM13 of register $d018 if you want different
colors for each pixel line. Unfortunately the Color RAM cannot be switched,
so the color selection of the pixels is not entirely free.

Also, the access to $d011 to create the Bad Line must not happen until cycle
14 of each raster line, or otherwise the RC would be cleared in every line
and the bitmap display would not be as desired. But this also implies that
the first three c-accesses of the VIC in each line do not read valid data,
because the first c-access in cycle 15 requires that BA should have gone low
in cycle 12 so that AEC can stay low in cycle 15 (AEC doesn't stay low until
three cycles after the negative edge of BA; there is no way around that).
Since the Bad Line was generated in cycle 14, while BA is now low in cycle
15 on the first c-access, AEC is still high, however, and so the internal
data bus gates D0-D7 of the VIC are closed and the chip reads the value $ff
instead of the video matrix data (the data bus gates D8-D11 are indeed open,
but this will be explained in section 3.14.6. in more detail). This stray
data is visible as 24-pixel wide stripes on the left side of the screen.

In practice, you place eight video matrices in memory that are used in the
following way: In the first raster line the first line of the first matrix,
in the second line the first line of the second matrix, etc., in the
eighth line the first line of the eighth matrix, in the ninth line the
second line of the first matrix, etc. With these eight matrices you can
cover a complete bitmap in line-wise fashion.

There are several flavors of the FLI mode, such as AFLI (Advanced FLI) which
uses the standard bitmap mode and simulates color blends with similarly
colored adjacent pixels, and IFLI (Interlaced FLI) that alternates between
two frames in a simulated interlace mode.

3.14.4. Linecrunch
------------------

By manipulating YSCROLL, you have even more possibilities for controlling
the Bad Lines. You may also abort a Bad Line before its correct completion
by negating the Bad Line Condition within an already begun Bad Line before
cycle 14. This his several consequences:

 · The graphics data is in display state, so graphics are displayed.
 · The RC is not reset. If you abort the very first line of a frame this
   way, the RC is still at 7 from the last line of the previous frame.
 · In cycle 58 of the line the RC is still 7, so the sequencer goes to idle
   state and VCBASE is loaded from VC. But since the sequencer has been in
   display state within the line, VC has been incremented after every
   g-access, so VCBASE has now been effectively increased by 40. The RC
   doesn't overflow, it stays at 7.

With this procedure you have reduced the display of a text line to its last
raster line, because as VCBASE has been incremented by 40, the VIC continues
with the next line. This effect if therefore called "Linecrunch": You can
"crunch" single text lines with it.

If you now do this in every raster line, the RC will always stay at 7 and
there will be no c-accesses, but VCBASE is incremented by 40 in every line.
This eventually makes VCBASE cross the 1000 byte limit of the video matrix
and the VIC will display the last, normally invisible, 24 bytes of the
matrix (where also the sprite data pointers are stored). VCBASE wraps around
to zero when reaching 1024.

By crunching whole text lines to one raster line each you have the
possibility to quickly scroll the screen contents upwards by large distances
without moving bytes in the graphics memory, in a similar way as you can
scroll it downwards with FLD. The only disturbing side effect is that the
crunched lines will pile up near the upper screen border, looking awkward.
Here it is possible to use one of the invalid graphics modes to blank out
these lines.

3.14.5. Doubled text lines
--------------------------

The display of a text line is normally finished after 8 raster lines,
because then RC=7 and in cycle 58 of the last line the sequencer goes to
idle state (see section 3.7.2.). But if you now assert a Bad Line Condition
between cycles 54-57 of the last line, the sequencer stays in display state
and the RC is incremented again (and thus overflows to zero). The VIC will
then in the next line start again with the display of the previous text
line. But as no new video matrix data has been read, the previous text line
is simply displayed twice.

3.14.6. DMA delay / VSP
-----------------------

The most sophisticated Bad Line manipulation is to create a Bad Line
Condition in cycles 15-53 of a raster line of display window, in which the
graphics data sequencer is in idle state, for example by modifying register
$d011 so that YSCROLL is now equal to the lower three bits of RASTER.

The VIC will then set BA low immediately in the next cycle, switch to
display state and start reading from the video matrix. The processor is now
stopped because BA is low and it wants to read the next opcode. However, AEC
still follows ϕ0 for three cycles before also staying at the low state. This
behavior (AEC not until three cycles after BA) is hardwired in the VIC and
cannot be avoided.

Nevertheless, the VIC accesses the video matrix, or at least it tries,
because as long as AEC is still high in the second clock phase, the address
and data bus lines D0-D7 of the VIC are in tri-state in the first three
cycles, so the VIC reads the value $ff from D0-D7 instead of the data from
the video matrix. The data lines D8-D13 of the VIC, however, don't have
tri-state drivers and are always set to input. But the VIC doesn't get valid
Color RAM data from there either, because with AEC being high, the 6510 is
still considered the bus master and unless it by chance wants to read the
next opcode from the Color RAM, the chip select input of the Color RAM is
not active. Instead, a 4 bit analog (!) switch, U16, connects the data bits
D0-D3 of the processor with the Color RAM data bits D8-D13. This connection
is always in place when AEC is high and allows the processor to access the
Color RAM if desired. To make a long story short: In the first three cycles
after BA went low the VIC reads $ff for the character pointers, and for the
color information the lower 4 bits of the opcode after the access to $d011.
Only then can it read regular video matrix data.

This data is stored just as usual at the start of the internal video
matrix/color line, and VC gets incremented after each following g-access
(with the generation of the Bad Line, the sequencer has also been put into
display state). The c- and g-accesses are continued until cycle 54. But
since the accesses started in the middle of a line, less than 40 of them
took place so VC is no longer a multiple of 40 at the end of the line.
Because of the way VC works (see section 3.7.2.), this "misalignment"
continues for all following lines. So the entire screen appears scrolled to
the right by as many characters as the number of cycles the $d011 access
took place after cycle 14. As the c-accesses within this line started later
than in a normal Bad Line, this procedure is called "DMA Delay" (or VSP for
"Virtual Screen Position").

With this method it is possible to scroll the complete screen sideways by
large distances (which also works with bitmap graphics in the same way
because the VC is also used for accessing the bitmap data) without having to
move the graphics memory with the processor. If you now combine DMA Delay
with FLD and Linecrunch, you can scroll entire graphics screens by almost
arbitrarily large distances in any direction, using very little computing
time.

Experimenting with DMA Delay (and with Bad Line effects in general) is also
the best method for discovering the internal functions of the VIC,
especially of RC and VC, and for determining in which cycles certain things
happen inside the VIC.

It should also be mentioned that DMA Delay can not only be achieved by
manipulating YSCROLL but also with the DEN bit of register $d011. To do
this, you have to set YSCROLL to zero so that raster line $30 becomes a bad
line and switch DEN from "0" to "1" in the middle of that line. This is
because Bad Lines can only occur if the DEN bit has been set for at least
one cycle in line $30, and if YSCROLL is zero a Bad Line Condition will
occur in line $30 as soon as DEN is set.

3.14.7 Sprite stretching / Sprite crunch
----------------------------------------

As the sprite circuitry is simpler than that for the text graphics, there
are not as many special effects possible with sprites, but among them is a
very interesting effect that takes advantage of the way the sprite Y
expansion works: By modifying the MxYE bits in register $d017 it is not only
possible to decide for each individual sprite line if it should be doubled,
but you can also repeat a single line three or more times and therefore
expand a sprite vertically by an arbitrary scaling factor.

This effect can be explained as follows (see section 3.8.1.):

Let's say that we are in cycle 55 of a raster line in which sprite 0 is
turned on, and whose Y coordinate matches the Y coordinate of the sprite, so
we are in the line before the sprite will be displayed. Suppose that the
M0YE bit is set. The VIC will then turn on the DMA for sprite 0, clear
MCBASE, and set the advance line flip-flop, which is then inverted in the
next cycle because of the set M0YE bit. BA goes to low state to allow the
VIC to access the sprite data in the second clock phases of cycles 58 and
59. In the first phase of cycle 58, MC is loaded from MCBASE (and so cleared
to zero as well), and the p-access for the sprite is performed. The VIC then
carries out the three s-accesses and increments MC after each access so it
now has the value 3.

Now you wait for cycle 16 of the following line. As the advance line
flip-flop is not set, MCBASE will still stay at zero. Now you clear the M0YE
bit, and thereby set the flip-flop, but then immediately set M0YE to "1"
again. Because M0YE remains set, the flip-flop will be inverted again in
cycle 56, and is therefore reset (if M0YE hadn't been cleared, the flip-flop
would now be set). But this is exactly the same state in which the VIC
already was in cycle 56 of the previous line. So the VIC "thinks" that it is
still in the first raster line of an expanded sprite and, since MC is still
zero, it will proceed to read the first sprite line twice more from memory,
three times in total: The first sprite line has been tripled.

Another interesting effect, known as "sprite crunch", can be achieved by
proceeding exactly as outlined above, but not clearing the M0YE bit after
cycle 16 but in the second phase of cycle 15. MCBASE will then be set to 1,
and the next sprite line is read from memory with MC=1..3, which is one byte
higher than normal. This misalignment continues in the entire display of the
sprite. The condition MC=63 for turning off the sprite DMA in cycle 16 is
therefore also not met, and the sprite is effectively displayed twice in a
row. Not until the end of the second display does the VIC finally turn off
the DMA when MC reaches 63.


4. The addresses 0 and 1 and the $de00 area
-------------------------------------------

The address range $de00-$dfff of the 6510 (see 2.4.1.) is reserved for
external expansions of the C64 and normally not connected to any other
devices (RAM, I/O). A read access will fetch data that looks random at first
sight. The same is true for the upper nybbles of the addresses $d800-$dbff
(the Color RAM).

But on some C64 models, this data turns out to be not "random" at all but
rather identical to the data that the VIC has read from memory in the first
phase of the clock cycle. This effect is however not reproducible on all
machines and not always reliable.

Apart from the fact that this opens up the possibility of measuring the VIC
timing completely in software (the timing diagrams in [4] on which the
diagrams in this article are based have, for example, been created using
this method), you can also make the 6510 execute programs in the $de00-area
or in the Color RAM if the VIC displays graphics in such a way that the 6510
always gets valid opcodes from the graphics data read by the VIC.

With a similar effect you can also write to RAM addresses 0 and 1 from the
processor. These are normally not accessible as the internal data direction
register and data register of the 6510 I/O port are mapped to these
addresses, and the data bus drivers of the processor stay in tri-state on a
write access. But the R/W line is still set to low state, and so the byte
read by the VIC in the first clock phase will be written to RAM. If you want
to write a certain value to addresses 0 or 1 you only have to write an
arbitrary value to these addresses, taking care that the VIC has read the
value you want from RAM in the clock phase before.

The addresses 0 and 1 can of course also be read by the processor, either
via the $de00-area of with the aid of sprite collisions. For this, you make
the VIC display a bitmap starting at address 0 and move a sprite consisting
only of one pixel over the bits of the first two bytes of the bitmap.
Depending on whether the VIC detects a collision or not, you can find out
the state of the individual bits and put them together to one byte.


5. Revision history
-------------------

1996-08-28
- Original version

2000-02-10
- Corrected typos in sections 3.4, 3.6.3, and 3.8
- Minor editorial changes

2024-09-16
- Section 2.2: Added description of the ϕ0 pin
- Section 2.3: Added descriptions of the S/LUM, COLOR, and ϕCOLOR pins
- Section 3.3: Extended information about the VIC color palette
- Section 3.7.2: Corrected the explanation of the VMLI
- Sections 3.8.1 and 3.14.7: Corrected the explanation of sprite Y
  expansion
- Section 3.8.2: More detailed description of the interaction between
  sprite-sprite and sprite-foreground priorities
- Complete editorial revision

2024-09-29
- Section 3.12: Clarify raster interrupt behavior


Appendix A: Bibliography
------------------------

[1] Commodore Business Machines, "C64 Programmers Reference Guide",
    Appendix L: "6510 microprocessor data sheet", 1984

[2] ditto, Appendix N: "6566/6567 Video Interface Controller (VIC-II) Chip
    Specifications"

[3] ditto, Chapter 5, Section "Memory management on the Commodore 64"

[4] Marko Mäkelä, "The memory accesses of the MOS 6569 VIC-II and MOS 8566
    VIC-IIe Video Interface Controller" (AKA: Pal timing), 1994-07-15

[5] John West, Marko Mäkelä, "Documentation for the NMOS 65xx/85xx
    Instruction Set" (AKA: 64doc), 1994-06-03

[6] Albert J. Charpentier et al., "Digital sine-cosine generator",
    United States Patent 4,551,682, Nov. 5, 1985

[7] James W. Redfield, Albert J. Charpentier, "Display logic circuit for
    multiple object priority", United States Patent 4,561,659, Dec. 31, 1985

[8] Philip Timmermann, "Calculating the color palette of the VIC II"
    https://www.pepto.de/projects/colorvic/ (accessed 2024-09-06)


Appendix B: Acknowledgments
---------------------------

I want to thank

 - Marko Mäkelä, Andreas Boose, Pasi Ojala and Wolfgang Lorenz for the
   amount of work they put into the examination of the VIC
 - Kaspar Jensen for proof-reading the English version of this document and
   for his suggestions
 - Adam Vardy for pointing out that my description of idle state graphics
   display was wrong
 - Thilo Girmann for explaining the actual implementation of the VMLI on
   the VIC
 - Daniel Kahlin, Hannu Nuotio, Antti Lankila and Andreas Matthies for
   figuring out how sprite Y expansion really works
