home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.elysium.pl
/
ftp.elysium.pl.tar
/
ftp.elysium.pl
/
docs
/
programming
/
VIC-Article
< prev
next >
Wrap
Text File
|
2008-03-11
|
124KB
|
2,570 lines
The MOS 6567/6569 video controller (VIC-II)
and its application in the Commodore 64
by Christian Bauer
<bauec002@goofy.zdv.uni-mainz.de>
30.May 1996
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/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
3.14.7. Sprite stretching
4. The addresses 0 and 1 and the $de00 area
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) 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 hacking a computer up to
the 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 last years. 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 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 have been done with an oscilloscope directly on
the chip, most insights are based on test programs on the C64 and by
comparing them with the implementation in single cycle emulations like
"Frodo SC".
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 1MHz
in the C64.
Important signals:
°2 Processor clock output
This clock signal is the reference for the complete 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.
R/W This signal flags a read (R/W high) or write (R/W low) access.
IRQ If this input is held on low level, an interrupt sequence is
triggered unless interrupts are masked with the interrupt mask bit
in the status register. The interrupt sequence begins after two
or more clock cycles 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 may therefore expect that the processor cannot access the RAM
addresses 0 and 1 (as they are overlayed by the I/O port), but more
on this later...
2.3. 6567/6569 graphics chip
----------------------------
The 656* series graphics chip by MOS Technologies were originally designed
to be used in video games and graphics terminals. But as the sales in these
markets have 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] has been used,
featuring 3 text based (40x25 characters with 8x8 pixels each) and 2 bitmap
based (320x200 pixels) video modes, 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 the RAM refresh) and also has a light pen
input and interrupt possibilities.
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 neglectable with the exception of the 6567R56A.
Newer C64 versions are bearing the functionally equivalent chips 8562
(NTSC) and 8565 (PAL). In the following, only 6567/6569 will be mentioned,
but all statements are applicable for the 856* chips. There is also a 6566
designed to be connected to static RAM but this one was never used in C64s.
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 indicated that the bus is available to
the processor during the second clock phase (°2 high). BA is
normally high as the VIC accesses the bus mostly during the first
phase. But for the character pointer and sprite data accesses, the
VIC also needs the bus sometimes 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 the
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
there). 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 that 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
generated the signal °2 from it.
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 it is explained how these memory areas share
the address space as seen by the CPU and the VIC. After that, the basics of
memory access and DRAM handling are mentioned.
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 via the 6510 I/O port lines and control lines 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.
So 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 store 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 have "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 (it
will be explained in chapter 4 that these values are not really 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 repeated 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 access the complete 64KB main memory all the same because the 2
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 that you can select one of
4 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
appear anywhere. But as explained earlier, the VIC has a 12 bit data bus of
which the upper 4 bits are connected with 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
---------------------------------------
6510 and VIC are both based on a relatively simple hard-wired design. Both
chips make a memory access in EVERY clock cycle, even if that is not
necessary at all. E.g if the processor is busy executing an internal
operation like indexed addressing in one clock cycle, that really doesn't
require an access to memory, it nevertheless performs a read and discards
the read byte. The VIC only performs read accesses, while the 6510 performs
both reads and writes.
There are no wait states, no internal caches and no sophisticated access
protocols for the bus as seen with more modern processors. 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). So it has primary control over the bus and may "stun" the processor
sometime or another when it needs additional cycles for memory accesses.
Besides this, 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
both use the memory alternatively without disturbing each other.
However, the VIC sometimes needs more cycles than made available to it by
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. The first "p" read access stops
the 6510, at least after the third "p" as the 6510 never does more than 3
write accesses in succession. 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
appropriately modifying the VIC register $d011, it is possible to force a
bus take-over at extraordinary times. This is explained in chapter 3 as
well as the complete bus timing of a VIC raster line.
3. Description of the VIC
-------------------------
This chapter is about the single 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 by it.
It is important to note that the units for display and for the needed
memory accesses 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 e.g. display
graphics without previously having read data (in this case, the data which
are still in the buffer are 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 give "1" on reading
╖ The VIC registers are repeated each 64 bytes in the area $d000-$d3ff,
i.e. register 0 appears on addresses $d000, $d040, $d080 etc.
╖ The unused addresses $d02f-$d03f give $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 function on the VIC
6567/6569 examined as yet. 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.).
╖ Apart from the DEN bit in register $d011, all register modifications
have an immediate effect. E.g. you can change the border color with
register $d020 in the middle of the screen.
3.3. Color palette
------------------
The VIC has a hard-wired palette of 16 colors that are encoded with 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
3.4. Display generation and display window dimensions
-----------------------------------------------------
As usual for controlling CRTs, the VIC builds the video frame line by line.
The line number and the number of clock cycles per line are constant for
every VIC type. The VIC works character-based, every character consists 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, 320╫200 or 160╫200
pixels in the bitmap modes.
In this article, the specification of a position on the screen is done with
the raster line number as the Y coordinate (RASTER, register $d011/$d012)
and a 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, the raster line number is used as Y coordinate and the number of the
clock cycle within the line as X coordinate. As previously mentioned, 8
pixels make a clock cycle, so the specification of a sprite X coordinate is
eight times more precise than that of a cycle number.
The graphics are displayed 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 little tweaking; then you see that the display window
is part of a "display column" that is made up by the linear extension of
the display window to the top and bottom. With that you can divide the
border in 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 in 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 each be 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 are each extended by 4 pixels into the
display window, if CSEL=0 the left border is extended 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/YSCROLL (bits 0-2 of registers $d011 and $d016), the position
of the graphics inside the display window can be scrolled 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 keep the graphics aligned with the window, X/YSCROLL have to be 3 and 0
for 25 lines/40 columns and both 7 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 for the reference point to mark the
beginning of a raster line, the occurrence of the raster IRQ has been
chosen, 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 comes 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
(unnoticed by the processor) access for 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 is also done 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 lines
of each text line. So the position of the Bad Lines depends on the YSCROLL.
As you will see later, the whole 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 generate and take away 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
that is 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 (which
gives the current Y coordinate) to hold the X coordinates, so you cannot
simply read them 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 conclude from the text characters displayed at the same X
position to 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 a delay of 12 pixels).
So a different approach has been taken: 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. 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]). Not until now the sprite X
coordinates were used to be able 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 don'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 separated
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, it 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 resp. the bitmap; an area of 2048 bytes (bitmap:
8192 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 has
basically nothing to do with the Char ROM. The Char ROM only contains
prepared bit patterns that can be used as character generator, but you
can also store 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 that, the VIC does 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 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) of which the result 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 follows:
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 (abbreviated):
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 (abbreviated):
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 (abbreviated):
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|c048c048c048c048c04cccc04c80
The line "Cycl-#" show the number of the clock cycle within the raster
line. The line starts with cycle 1 and consists of 63 cycles on the 6569,
of 64 cycles on the 6567R56A and of 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 bus signals
with the same names. °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 Access to video matrix and Color RAM (c-access)
g Access to 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 you cannot see from the "Graph." line 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
on 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 and the display state.
- 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 8 bits of
each read byte are converted to 8 pixels by the sequencer. A "0" bit
displays the background color in register $d021, a "1" bit gives a black
pixel. With the exception of the ECM bit, this behavior is independent
of the display mode.
- In display state, c- and g-accesses take place, the addresses and
interpretation of the data depend on the selected display mode.
The transition from idle to display mode 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 not equal to zero in $3fff you can see the stripes
generated by the sequencer in idle state on the upper or lower side 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. They
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.
Besides this, there is a 6 bit counter with reset input that keeps track of
the position within the internal 40╫12 bit video matrix/color line where
read character pointers are stored resp. read again. I will call this
"VMLI" (video matrix line index) here.
There 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. These
data is internally read from the position specified by VMLI as well 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 in display state afterwards (this is always the case
if there is a Bad Line Condition), RC is incremented.
These rules normally see that VC counts all 1000 addresses of the video
matrix within the display frame and that RC counts the 8 pixel lines of
each text line. The behavior of VC and RC is largely determined by Bad Line
Conditions which you can control with the processor via YSCROLL, giving you
control of the VC and RC within certain limits.
3.7.3 Graphics modes
--------------------
The graphics data sequencer is capable of 7 different graphics modes. In
display state, the bits ECM, BMM and MCM (Extended Color Mode, Bit Map Mode
and Multi Color Mode) in the registers $d011 and $d016 select one of 6
modes (of the 8 possible bit combinations, 3 are "invalid" and generate the
same output, the color black), in idle state, the display is always done in
the same way, independent of ECM/BMM/MCM.
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 every pixel and reloaded with new
graphics data after every 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.
The address generator for the text/bitmap accesses (c- and g-accesses) has
basically 3 modes for the g-accesses (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).
The 9 graphics modes are now covered separately and the generated addresses
and the interpretation of the read data on c- and g-accesses is described.
For easy reference, the addresses are always given explicitly for every
mode although e.g. the c-accesses are always the same.
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 in 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. 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, every 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 for displaying four-colored characters at the cost 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, each two adjacent bits of the dot matrix
form one pixel. By this means, the resolution of a character of reduced to
4╫8 (the pixels are twice as wide, so the total width of the characters
doesn't change).
It is interesting that not only the bit combination "00" but also "01" is
regarded as "background" for the 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 (as in all bitmap modes), the VIC reads the graphics data from
a 320╫200 bitmap in which every 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, every bit in the bitmap directly corresponds to
one pixel on the screen. Foreground and background color can be arbitrarily
set for every 8╫8 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. 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 done with the upper two bits of the character pointer. This,
however, reduces the 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": Background |
| "1": Foreground |
+---------------------------------------+
| 4 pixels (2 bits/pixel) |
| |
| "00": Background | MC flag = 1
| "01": Background |
| "10": Foreground |
| "11": 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 also 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 is - roughly said - made up of four "sections" that are
each 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": Background |
| "1": Foreground |
+---------------------------------------+
3.7.3.8. Invalid bitmap mode 2 (ECM/BMM/MCM=1/1/1)
--------------------------------------------------
The last invalid mode also creates a black screen but it can also 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": Background |
| "01": Background |
| "10": Foreground |
| "11": Foreground |
+---------------------------------------+
3.7.3.9. Idle state
-------------------
In idle state, the VIC reads graphics data from address $3fff (resp. $39ff
if the ECM bit is set) and displays it as in standard text mode but with
the color of "1" pixels being always black.
Although the graphics in idle state always looks like a "standard" mode
(i.e. 1 bit/pixel) independent of the ECM/BMM/MCM bits, the MCM bit is not
completely inoperational. It still switches the sprite priority/collision
detection logic between standard mode and multicolor mode. In other words:
If the MCM bit is set in idle state, the sprite priority logic behaves as
in multicolor mode: It combines every 2 adjacent pixels and treats the bit
combinations "00" and "01" as background and "10" and "11" as foreground,
although the idle graphics doesn't change its appearance.
g-access (ECM=0)
Addresses
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 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 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
Data
+----+----+----+----+----+----+----+----+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+----+----+----+----+----+----+----+----+
| 8 pixels (1 bit/pixel) |
| |
| "0": Background color 0 ($d021) |
| "1": Black |
+---------------------------------------+
g-access (ECM=1)
Addresses
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 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) |
| |
| "0": Background color 0 ($d021) |
| "1": Black |
+---------------------------------------+
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 an arbitrary position on the screen, you can switch
them on and off one at a time with the bits of register $d015 (MxE), expand
them by the factor 2 in X and/or Y direction with registers $d017/$d01d
(with the 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). Besides, the VIC
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 3.11.).
The position of the top left corner of a sprite is specified with the
coordinate registers (MxX, MxY) belonging to it. There are 8 bits for the Y
coordinate and 9 bits for the X coordinate (the most significant bits 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.
These 63 bytes can be moved 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 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 done in every raster
line and not only when the belonging sprite is just displayed, 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 done in the three
half-cycles directly after the p-access belonging to the sprite within the
raster line. The VIC also uses the BA and AEC signals (as in 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, it
is always in the line before, see the timing diagrams in section 3.6.3.),
for every sprite in statically assigned cycles within the line.
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 sprite color
from registers $d027-$d02e belonging to the sprite in question. In
multicolor mode, two adjacent bits form one pixel, thus reducing the
resolution of the sprite to 12╫21 (the pixels are twice as wide).
Moreover, the sprites can be doubled in their size on the screen in X
and/or Y direction (X/Y expansion). For that, every sprite pixel simply
becomes twice as wide/tall, the resolution doesn't change. So a pixel of an
x-expanded multicolor sprite is four times as wide as a pixel of an
unexpanded standard 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 with half frequency.
But the Y expansion makes the sprite address generator read from the same
addresses in each two lines in sequence so that every sprite line is output
twice.
Every 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 counter with reset input.
Besides, there is one expansion flip flop per sprite that controls the
Y expansion.
The display of a sprite is done after the following rules (the cycle
numbers are only valid for the 6569):
1. The expansion flip flip is set as long as the bit in MxYE in register
$d017 corresponding to the sprite is cleared.
2. If the MxYE bit is set in the first phase of cycle 55, the expansion
flip flop is inverted.
3. 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) match 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 if the MxYE bit is
set the expansion flip flip is reset.
4. In the first phase of cycle 58, the MC of every sprite is loaded from
its belonging MCBASE (MCBASE->MC) and it is checked 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.
5. If the DMA for a sprite is turned on, three s-accesses are done 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 matches the X coordinate of the sprite
(even registers $d000-$d00e), and the bits that "fall off" are
displayed. If the MxXE bit belonging to the sprite in register $d01d is
set, the shift is done only every second pixel and the sprite appears
twice as wide. If the sprite is in multicolor mode, every two adjacent
bits form one pixel.
7. In the first phase of cycle 15, it is checked if the expansion flip flop
is set. If so, MCBASE is incremented by 2.
8. In the first phase of cycle 16, it is checked if the expansion flip flop
is set. If so, MCBASE is incremented by 1. After that, the VIC checks if
MCBASE is equal to 63 and turns of the DMA and the display of the sprite
if it is.
As the test in rule 3 is done 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
until 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
freely set a new X coordinate and sprite data pointer). It is therefore
possible to display more than 8 sprites on the screen.
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 4 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.
Once again 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, it has to be decided which element is displayed in
the foreground. To do this, every element has a priority assigned and only
the element with highest priority is displayed.
The sprites have a rigid 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, you have to distinguish the text/bitmap
graphics between foreground 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), cleared pixels belong to the background and set pixels to the
foreground. It should be noted that this is also valid for the graphics
generated in idle state although these are always displayed with 1
bit/pixel, independently of the MCM bit.
With the MxDP bits from register $d01b, you can separately specify for each
sprite if it should 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
+-----------------------+
Of course, the graphics elements with lower priority than an overlayed
sprite are visible where the sprite has a transparent pixel.
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 pixels.
Together with 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 all 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
ore 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.
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. There
comparators compare the X/Y position of the raster beam with one of two
hardwired values (depending on the state of the CSEL/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:
| CSEL=0 | CSEL=1
------+------------+-----------
Left | 31 ($1f) | 24 ($18)
Right | 335 ($14f) | 344 ($158)
And the vertical ones:
| 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. If the X coordinate reaches the right comparison value, the main border
flip flop is set.
2. If the Y coordinate reaches the bottom comparison value in cycle 63, the
vertical border flip flop is set.
3. If 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. If the X coordinate reaches the left comparison value and the Y
coordinate reaches the bottom one, the vertical border flip flop is set.
5. If 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. If 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 if 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) serves for switching on
and off the text/bitmap graphics. 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.). Then the upper/lower border is
not turned off.
So clearing the DEN bit will normally prevent Bad Lines (and thus c- and
g-accesses) from occuring and make the whole screen display the border
color.
3.11. Lightpen
--------------
On a negative edge on 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 next vertical blanking interval.
As the LP input of the VIC is connected to the keyboard matrix as are all
lines of the joystick ports, it can also be controlled by software. This is
done with bit 4 of port B of CIA A ($dc01/$dc03). This allows to determine
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 e.g. be used to synchronize
raster interrupt routines on exact cycles.
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. E.g. 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 can also additionally trigger an interrupt on a negative edge on
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. This is done with the IRQ output that is directly
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. Every 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 belonging bit in the enable register is
set, the IRQ line is held low and so the interrupt is triggered in the
processor. So the four interrupt sources can be independently enabled and
disabled with the enable bits. As the VIC - as described - doesn't clear
the interrupt latch by itself, the processor has to do it before the I
flag is cleared resp. before the processor returns from the interrupt
routine. Otherwise the interrupt will be triggered again 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 0 of every line (for line
| | 0, in cycle 1).
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 resp. $d01f contained the
value zero before the collision). To trigger further interrupts after a
collision, the concerning 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 does five read accesses in every raster line for the refresh of 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.
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/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. So the border is basically not 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 is e.g. never turned on
and you can see the graphics in the border area that is normally covered by
the border. The technique is called "hyperscreen" or "opening the border".
However, the graphics displayable in the border area is mainly limited to
sprites, as 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 also do something sensible with 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, you switch to 25-line-border
by setting the RSEL bit.
2. Now you 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 you clear the RSEL bit. The comparator is switched and now sets the
vertical flip flop at line 247. But this line is already passed and thus
the VIC "forgets" to turn on the vertical border.
4. After raster line 251 you 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 is never turned off and
covers the whole screen (this is the same when the DEN bit is cleared, but
Bad Lines still occur). But this is not very sensible.
The left/right border can be turned of with the CSEL bit in a similar way.
However, the timing is much more critical. Whereas for the vertical border,
you have 4 raster lines time 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 with it before the vertical border flip flop is set
(i.e. outside of the upper/lower border), or also open the upper/lower
border, 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 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 orientates itself
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.). So 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 each. The distance between two text lines can be
arbitrarily increased if only you hold back the next Bad Line long enough.
This effect is called "Flexible Line Distance" (FLD).
E.g. 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 complete 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
may also artificially create additional Bad Lines 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 single 8╫8 pixel
blocks can be colored individually in bitmap modes. But if you make every
raster line a Bad Line by appropriately modifying YSCROLL, the VIC will
read from the video matrix in every line and so it will also read new color
information for every 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
3.7.2.). So the VIC reads from the same addresses in the video matrix as in
the previous line. As you cannot change the video matrix fast enough with
the processor, you have to switch the base address of the video matrix with
the bits VM10-VM13 of register $d018 (unfortunately the Color RAM cannot be
switched, so the color selection of the pixels is not completely free).
Besides, the access to $d011 to create the Bad Line may not happen until
cycle 14 of each raster line, or else 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 already 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). But as the Bad Line was first created in cycle 14, it's true
that BA is low in cycle 15 on the first c-access, but AEC is high and so
the internal data bus drivers D0-D7 of the VIC are closed and as the chip
is manufactured in NMOS technology, it reads the value $ff and not the
video matrix data (the data bus drivers D8-D11 are indeed open, but this is
explained in section 3.14.6. in more detail) which is visible as 24 pixel
wide stripes on the left side of the screen.
Practically you store 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
line-wise cover a complete bitmap.
There are several flavors of the FLI mode, such as AFLI (Advanced FLI)
which uses the standard bitmap mode and simulates color blends by similarly
colored adjacent pixels, and IFLI (Interlaced FLI) that alternates between
two frames in a sort of interlace mode.
3.14.4. Linecrunch
------------------
By manipulating YSCROLL, you have even more possibilities to control 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 as 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 displays 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 up by large distances
without moving bytes in the graphics memory, in a similar way as you can
scroll it down with FLD. The only disturbing side effect is that the
crunched lines pile up at the upper screen border, looking awkward. But
here you can 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
-----------------
The most sophisticated Bad Line manipulation is to create a Bad Line
Condition within cycles 15-53 of a raster line in the display window in
which the graphics data sequencer is in idle state, e.g. by modifying
register $d011 so that YSCROLL is equal to the lower three bits of RASTER.
The VIC will then set BA to 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 °2 for three cycles before also staying at 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 drivers D0-D7 of the VIC are in tri-state and the VIC reads
the value $ff from D0-D7 instead of the data from the video matrix in the
first three cycles. 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 as AEC is high, the 6510 is
still considered the bus master and unless it doesn't by chance want 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 data bits D8-D13. This connection
is always in place when AEC is high and should allow 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 as character pointers and
as color information the lower 4 bits of the opcode after the access to
$d011. Not until then, regular video matrix data is read.
These data are stored just as usual at the start of the internal video
matrix/color line and VC is 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 as
the accesses started in the middle of a line, less than 40 accesses took
place so VC has been incremented by a total of less than 40 in this raster
line and no longer is a multiple of 40 as it normally always is at the end
of a raster line. Because of the working of VC (see section 3.7.2.), this
"misalignment" is continued for all following lines. So the whole screen
seems to be scrolled to the right by as much characters as the number of
cycles the $d011 access was done after cycle 14. As the c-accesses within
the line start later than in a normal Bad Line, this procedure is called
"DMA Delay".
With this, it is possible to scroll the complete screen sideways by large
distances (this also works with bitmap graphics as with text screens as 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 complete graphics screens without using much
computing time by almost arbitrarily large distances in all directions.
Experimenting with the DMA Delay (and with Bad Line effects in general) is
also the best method to discover the internal functions of the VIC,
especially of RC and VC, and to determine in which cycles certain things
are done 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 reset to set in the middle of the line. This is
because Bad Line 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
------------------------
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 every single sprite line if it should be
doubled, but you can also have single lines repeated three or more times
and so expand a sprite by arbitrary scaling factors.
This effect can be understood 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 is displayed. Suppose that the M0YE
bit is set. The VIC will then turn on the DMA for sprite 0 and clear MCBASE
and the expansion flip flop. BA goes to low state so that the VIC is able
to access in the second clock phases of cycles 58 and 59. In cycle 58, MC
is loaded from MCBASE and so cleared as well, and the p-access for the
sprite is done. Afterwards, the three s-accesses are carried out and MC is
incremented after each access so it now has the value 3.
Now you wait for cycle 16 of the following line. As the expansion flip flop
is reset, MCBASE still stays at zero. Then you first clear the M0YE bit and
thereby set the flip flop, but immediately set the M0YE again. The flip
flop is now inverted in cycle 55, because M0YE is set, and is thus reset
again (if the M0YE hadn't been cleared, the flip flop would now be set).
But this is exactly the same state in which the VIC was also in cycle 55 of
the previous line. So the VIC "thinks" that it is still in the first raster
line of an expanded sprite line and (as MC is still zero) and it will read
the first sprite line twice more from memory, three times in total: The
first sprite line has been tripled.
Another interesting effect can be achieved by proceeding exactly as
outlines above and not clearing the M0YE bit after cycle 16 but in the
second phase of cycle 15. MCBASE will then only be incremented by 1 and the
next sprite line is read from memory with MC=1..3, that is one byte higher
than normal. This "misalignment" is continued in the complete display of
the sprite. Therefore, the condition MC=63 for turning off the sprite DMA
in cycle 16 is also not met and the sprite is effectively displayed twice
in sequence. Not until the end of the second display, the DMA is turned off
when MC is 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 with any other
unit (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, this data is 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 precisely.
Apart from the fact that this gives the possibility to measure the VIC
timing completely by software (the timing diagrams in [4] on which the
diagrams in this article are based, have e.g. been created with this
method), you can also make the 6510 execute programs in the $de00-area or
in the Color RAM if the VIC displays a graphics in such a way that the 6510
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. They are normally not available 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 stay in tri-state on a write access.
But the R/W line is set to low state (this can be explained as the I/O port
has been integrated afterwards into the existing design of the 6502) and so
the byte read by the VIC in the first clock phase is 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 and take care that the VIC read the
desired value from RAM in the clock phase before.
The addresses 0 and 1 can of course also be read by the processor. Either
with 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 single bits of the first two bytes of
the bitmap. Depending on whether a collision has been detected or not, you
can find out the state of the single bits and put them together to one
byte.
Appendix A: Bibliography
------------------------
[1] Commodore Business Machines, "C64 Programmers Reference Guide",
Appendix L: "6510 microprocessor data sheet", 1984
[2] dto., Appendix N: "6566/6567 Video Interface Controller (VIC-II) Chip
Specifications"
[3] dto., 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), 15.07.1994
[5] John West, Marko MΣkelΣ, "Documentation for the NMOS 65xx/85xx
Instruction Set" (AKA: 64doc), 03.06.1994
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