2730 lines
129 KiB
Plaintext
2730 lines
129 KiB
Plaintext
|
||
The MOS 6567/6569 video controller (VIC-II)
|
||
and its application in the Commodore 64
|
||
|
||
by Christian Bauer
|
||
<www.cebix.net>
|
||
|
||
2024-09-29
|
||
|
||
|
||
|
||
Contents
|
||
--------
|
||
|
||
1. Introduction
|
||
2. The architecture of the Commodore 64
|
||
2.1. Overview
|
||
2.2. 6510 processor
|
||
2.3. 6567/6569 graphics chip
|
||
2.4. Memory
|
||
2.4.1. Memory map as seen by the 6510
|
||
2.4.2. Memory map as seen by the VIC
|
||
2.4.3. Memory access of 6510 and VIC
|
||
3. Description of the VIC
|
||
3.1. Block diagram
|
||
3.2. Registers
|
||
3.3. Color palette
|
||
3.4. Display generation and display window dimensions
|
||
3.5. Bad Lines
|
||
3.6. Memory access
|
||
3.6.1. The X coordinates
|
||
3.6.2. Access types
|
||
3.6.3. Timing of a raster line
|
||
3.7. Text/bitmap display
|
||
3.7.1. Idle state / display state
|
||
3.7.2. VC and RC
|
||
3.7.3. Graphics modes
|
||
3.7.3.1. Standard text mode (ECM/BMM/MCM=0/0/0)
|
||
3.7.3.2. Multicolor text mode (ECM/BMM/MCM=0/0/1)
|
||
3.7.3.3. Standard bitmap mode (ECM/BMM/MCM=0/1/0)
|
||
3.7.3.4. Multicolor bitmap mode (ECM/BMM/MCM=0/1/1)
|
||
3.7.3.5. ECM text mode (ECM/BMM/MCM=1/0/0)
|
||
3.7.3.6. Invalid text mode (ECM/BMM/MCM=1/0/1)
|
||
3.7.3.7. Invalid bitmap mode 1 (ECM/BMM/MCM=1/1/0)
|
||
3.7.3.8. Invalid bitmap mode 2 (ECM/BMM/MCM=1/1/1)
|
||
3.7.3.9. Idle state
|
||
3.8. Sprites
|
||
3.8.1. Memory access and display
|
||
3.8.2. Priority and collision detection
|
||
3.9. The border units
|
||
3.10. Display Enable
|
||
3.11. Lightpen
|
||
3.12. VIC interrupts
|
||
3.13. DRAM refresh
|
||
3.14. Effects and applications
|
||
3.14.1. Hyperscreen
|
||
3.14.2. FLD
|
||
3.14.3. FLI
|
||
3.14.4. Linecrunch
|
||
3.14.5. Doubled text lines
|
||
3.14.6. DMA delay / VSP
|
||
3.14.7. Sprite stretching / Sprite crunch
|
||
4. The addresses 0 and 1 and the $de00 area
|
||
5. Revision history
|
||
|
||
Appendix A: Bibliography
|
||
Appendix B: Acknowledgments
|
||
|
||
|
||
|
||
1. Introduction
|
||
---------------
|
||
|
||
This paper is an attempt to summarize the results of various people's
|
||
examinations of the graphics chip "6567/6569 Video Interface Controller
|
||
(VIC-II)" (simply called "VIC" in the following) which is used in the
|
||
legendary Commodore 64, and to provide a complete reference to its specified
|
||
and unspecified properties. It is primarily intended for C64 programmers and
|
||
authors of C64 emulators, but should also be interesting to "outsiders"
|
||
interested in hardware design and programming, and utilizing a computer up
|
||
to its last bits. For this purpose, some general information (e.g. the C64
|
||
memory map) already known to experienced C64 programmers has been included
|
||
as well.
|
||
|
||
The description of the unspecified properties is based on tests done by
|
||
Marko Mäkelä, Andreas Boose, Pasi Ojala, Wolfgang Lorenz and myself (not to
|
||
mention numerous others) during the 1990s. It also covers internal registers
|
||
and workings of the VIC. As no schematics of the VIC are available it can of
|
||
course only be speculative, but in all cases a descriptive model has been
|
||
chosen that explains the observed phenomena with the minimally required
|
||
circuitry. E.g. for the video matrix counter (VC), a model with two simple
|
||
counters was given preference to a more elaborate one with a +40 adder.
|
||
|
||
Although some measurements were done with an oscilloscope directly on the
|
||
chip, most insights have been gathered via test programs on the C64, and by
|
||
comparing them with the implementation in single cycle emulations like
|
||
"Frodo".
|
||
|
||
|
||
2. The architecture of the Commodore 64
|
||
---------------------------------------
|
||
|
||
This chapter gives an overview of the basic hardware architecture of the C64
|
||
and the integration of the VIC into the system.
|
||
|
||
2.1. Overview
|
||
-------------
|
||
|
||
The C64 basically consists of the following units:
|
||
|
||
· 6510 8-bit microprocessor
|
||
· 6567/6569 VIC-II graphics chip
|
||
· 6581 SID sound chip
|
||
· Two 6526 CIA I/O chips
|
||
· 64KB DRAM (64K*8 bit) main memory
|
||
· 0.5KB SRAM (1K*4 bit) Color RAM
|
||
· 16KB ROM (16K*8 bit) for operating system and BASIC interpreter
|
||
· 4KB ROM (4K*8 bit) character generator
|
||
|
||
Most chips are manufactured in NMOS technology.
|
||
|
||
2.2. 6510 processor
|
||
-------------------
|
||
|
||
The 6510 microprocessor [1] has an 8-bit data bus and a 16-bit address bus,
|
||
and is object-code compatible with the famous 6502. It has two external
|
||
interrupt inputs, one maskable (IRQ) and one non-maskable (NMI), and as a
|
||
special feature a 6-bit wide bidirectional I/O port. It is clocked at
|
||
approximately 1 MHz in the C64.
|
||
|
||
Important signals:
|
||
|
||
ϕ2 Processor clock output
|
||
This clock signal is the reference for the entire bus timing. Its
|
||
frequency is 1022.7 kHz (NTSC models) or 985.248 kHz (PAL models).
|
||
One period of this signal corresponds to one clock cycle consisting
|
||
of two phases: ϕ2 is low in the first phase and high in the second
|
||
phase (hence the name 'ϕ2' for "phase 2"). The 6510 only accesses the
|
||
bus in the second clock phase, the VIC normally only in the first
|
||
phase.
|
||
|
||
ϕ0 Processor clock input
|
||
This signal, with the same frequency as ϕ2, is generated by the
|
||
VIC (see section 2.3.) and used to derive the ϕ2 clock.
|
||
|
||
R/W This signal indicates a read (R/W high) or write (R/W low) bus
|
||
access.
|
||
|
||
IRQ If this input is held low an interrupt sequence is triggered, unless
|
||
interrupts are masked with the interrupt mask bit in the processor
|
||
status register. The interrupt sequence begins at least two clock
|
||
cycles later at the start of the next instruction. With this pin, the
|
||
VIC can trigger an interrupt in the processor. Interrupts are only
|
||
recognized if the RDY line is high.
|
||
|
||
RDY If this line is low during a read access, the processor stops with
|
||
the address lines reflecting the current address being fetched. It
|
||
is ignored during write accesses. In the C64, RDY is used to stop
|
||
the processor if the VIC needs additional bus cycles for character
|
||
pointer and sprite data accesses. It is connected to the BA signal
|
||
on the VIC.
|
||
|
||
AEC This pin tri-states the address lines. This is used for making the
|
||
processor address bus inactive during VIC accesses. The signal is
|
||
connected to the AEC output on the VIC.
|
||
|
||
P0-P5 This is the built-in 6-bit I/O port. Each line can be individually
|
||
programmed as input or output. A data direction register and a data
|
||
register are internally mapped to addresses 0 and 1, respectively.
|
||
You might therefore expect that the processor cannot access the RAM
|
||
addresses 0 and 1, as they are overlaid by the I/O port, but more
|
||
on this in chapter 4...
|
||
|
||
2.3. 6567/6569 graphics chip
|
||
----------------------------
|
||
|
||
The 656* series graphics chips by MOS Technologies were originally designed
|
||
to be used in video games and graphics terminals. But as the sales in these
|
||
markets had been rather poor, Commodore decided to use the chips when they
|
||
were planning to make their own home computers.
|
||
|
||
In the C64, the "Video Interface Controller II (VIC-II)" [2] is used,
|
||
featuring 3 text (or tile) based video modes (40x25 characters with 8x8
|
||
pixels each) and 2 bitmap based video modes (320x200 pixels), 8 hardware
|
||
sprites and a fixed palette of 16 colors. It can manage up to 16KB of
|
||
dynamic RAM, including the generation of RAS and CAS and handling the RAM
|
||
refresh, and also has a light pen input and interrupt capabilities.
|
||
|
||
Two VIC types appear in the C64: The 6567 in NTSC machines and the 6569 in
|
||
PAL machines. There are several mask steppings of both types, but the
|
||
differences are mostly negligible with the exception of the 6567R56A. Newer
|
||
C64 versions are employing the functionally equivalent chips 8562 (NTSC) and
|
||
8565 (PAL). In the following, only 6567/6569 will be mentioned, but all
|
||
information is also applicable to the 856* chips. There is also a 6566
|
||
designed to be connected to static RAM but this one was never used in C64s
|
||
(it was used, however, in the somewhat similar Commodore MAX computer).
|
||
|
||
Important signals:
|
||
|
||
A0-A13 The 14-bit video address bus used by the VIC to address 16KB of
|
||
memory. The address bits A0-A5 and A8-A13 are multiplexed in pairs
|
||
(i.e. A0/A8, A1/A9 etc.) on one pin each. The bits A6-A11 are
|
||
(additionally) available on separate lines.
|
||
|
||
D0-D11 A 12-bit wide data bus over which the VIC accesses the memory. The
|
||
lower 8 bits are connected to the main memory and the processor
|
||
data bus, the upper 4 bits are connected to a special 4 bit wide
|
||
static memory (1024 addresses, A0-A9) used for storing color
|
||
information, the Color RAM.
|
||
|
||
IRQ This output is wired to the IRQ input on the processor and makes it
|
||
possible for the VIC to trigger interrupts. The VIC has four
|
||
interrupt sources: On reaching a certain raster line (raster
|
||
interrupt), on the collision of two or more sprites, on the
|
||
collision of sprites with graphics data and on a negative edge on
|
||
the light pen input.
|
||
|
||
BA With this signal, the VIC indicates that the bus is available to
|
||
the processor during the second clock phase (ϕ2 high). BA is
|
||
normally high, as the VIC usually accesses the bus during the first
|
||
phase only. But for the character pointer and sprite data accesses,
|
||
the VIC also needs the bus during the second phase. In this case, BA
|
||
goes low three cycles before the VIC access. After that, AEC remains
|
||
low during the second phase and the VIC performs its accesses. Why
|
||
three cycles? BA is connected to the RDY line of the processor as
|
||
mentioned, but this line is ignored on write accesses (the CPU can
|
||
only be interrupted on reads), and the 6510 never does more than
|
||
three writes in sequence (see [5]).
|
||
|
||
AEC This pin is wired to the processor signal with the same name (see
|
||
above). It reflects the state of the data and address line drivers
|
||
of the VIC. If AEC is high, they are in tri-state. AEC is normally
|
||
low during the first clock phase (ϕ2 low) and high during the second
|
||
phase so the VIC can access the bus during the first phase and the
|
||
6510 during the second phase. If the VIC also needs the bus in the
|
||
second phase, AEC remains low.
|
||
|
||
LP This input is intended for connecting a light pen. On a negative
|
||
edge, the current position of the raster beam is latched to the
|
||
registers LPX and LPY. As this pin shares a line with the keyboard
|
||
matrix, it can also be accessed by software.
|
||
|
||
ϕIN This is the feed for the pixel clock of 8.18 MHz (NTSC) or 7.88 MHz
|
||
(PAL) that is generated from the crystal frequency. Eight pixels
|
||
are displayed per bus clock cycle (ϕ2).
|
||
|
||
ϕ0 From the pixel clock on ϕIN, the VIC generates the system clock of
|
||
1.023 MHz (NTSC) or 0.985 MHz (PAL) by dividing ϕIN by eight. It is
|
||
available on this pin and fed into the processor which in turn
|
||
generates the signal ϕ2 from it.
|
||
|
||
ϕCOLOR This input receives a 14.31818 MHz (NTSC) or 17.734475 MHz (PAL)
|
||
signal from which the VIC derives its color output signal. Its
|
||
frequency corresponds to four times the NTSC or PAL color burst
|
||
signals of 3.579545 MHz and 4.43361875 MHz, respectively.
|
||
|
||
S/LUM This pin outputs the horizontal and vertical sync signals and the
|
||
luminosity information for the image produced by the VIC. The VIC
|
||
does not support interlace and always outputs a progressive image.
|
||
|
||
COLOR This pin outputs the composite color information for the image,
|
||
including the color burst signal.
|
||
|
||
2.4. Memory
|
||
-----------
|
||
|
||
Three memory areas in the C64 are involved with the graphics:
|
||
|
||
· The 64KB main memory
|
||
· The 1K*4 bit Color RAM
|
||
· The 4KB character generator ROM (Char ROM)
|
||
|
||
In the following two sections we explain how these memory areas share the
|
||
address space as seen by the CPU and the VIC. After that, we will cover the
|
||
basics of memory access and DRAM handling.
|
||
|
||
2.4.1 Memory map as seen by the 6510
|
||
------------------------------------
|
||
|
||
The 6510 can address 64KB linearly with its 16 address lines. With the aid
|
||
of a special PAL chip in the C64, many different memory configurations can
|
||
be used, controlled via the 6510 I/O port lines and additional signals on
|
||
the expansion port (see [3]). Only the standard configuration will be
|
||
discussed here as the other configurations don't change the position of the
|
||
different areas. They only map in additional areas of the main memory.
|
||
|
||
This is the memory map as seen by the 6510:
|
||
|
||
|
||
The area at $d000-$dfff with
|
||
CHAREN=1 CHAREN=0
|
||
|
||
$ffff +--------------+ /$e000 +----------+ +----------+
|
||
| Kernal ROM | / | I/O 2 | | |
|
||
$e000 +--------------+/ $df00 +----------+ | |
|
||
|I/O, Char ROM | | I/O 1 | | |
|
||
$d000 +--------------+\ $de00 +----------+ | |
|
||
| RAM | \ | CIA 2 | | |
|
||
$c000 +--------------+ \$dd00 +----------+ | |
|
||
| Basic ROM | | CIA 1 | | |
|
||
$a000 +--------------+ $dc00 +----------+ | Char ROM |
|
||
| | |Color RAM | | |
|
||
. RAM . | | | |
|
||
. . $d800 +----------+ | |
|
||
| | | SID | | |
|
||
$0002 +--------------+ |registers | | |
|
||
| I/O port DR | $d400 +----------+ | |
|
||
$0001 +--------------+ | VIC | | |
|
||
| I/O port DDR | |registers | | |
|
||
$0000 +--------------+ $d000 +----------+ +----------+
|
||
|
||
|
||
Basically, the 64KB main memory can be accessed in a linear fashion, but
|
||
they are overlaid by ROM and register areas at several positions. A write
|
||
access to a ROM area will change the byte in the RAM lying "under" the ROM.
|
||
The 6510 I/O port is mapped to addresses $0000 (for the data direction
|
||
register) and $0001 (for the data register).
|
||
|
||
In the area at $d000-$dfff you can switch between the I/O chip registers and
|
||
the Color RAM, or the character generator ROM, with the signal CHAREN which
|
||
is bit 2 of the 6510 I/O port. The Color RAM is mapped at $d800-$dbff and
|
||
connected to the lower 4 data bits. The upper 4 bits are open and produce
|
||
"random" values on reading. The two areas named "I/O 1" and "I/O 2" are
|
||
reserved for expansion cards and also open under normal circumstances.
|
||
Hence, a read access will fetch "random" values here too. As we will explain
|
||
in chapter 4 these values are not fully random. Reading from open addresses
|
||
fetches the last byte read by the VIC on many C64s.
|
||
|
||
The 47 registers of the VIC are mapped in at $d000. Due to the incomplete
|
||
address decoding, they are mirrored every 64 bytes in the area $d000-$d3ff.
|
||
|
||
2.4.2 Memory map as seen by the VIC
|
||
-----------------------------------
|
||
|
||
The VIC has only 14 address lines, so it can only address 16KB of memory. It
|
||
can nevertheless access the entire 64KB of main memory because the two
|
||
missing address bits are provided by one of the CIA I/O chips (they are the
|
||
inverted bits 0 and 1 of port A of CIA 2). With these you can select one of
|
||
four 16KB banks for the VIC at a time.
|
||
|
||
The (extended) memory map as seen by the VIC looks like this:
|
||
|
||
|
||
$ffff +----------+ --
|
||
| |
|
||
| |
|
||
| |
|
||
| RAM | Bank 3
|
||
| |
|
||
| |
|
||
| |
|
||
$c000 +----------+ --
|
||
| |
|
||
| RAM |
|
||
| |
|
||
$a000 +----------+ Bank 2
|
||
| Char ROM |
|
||
$9000 +----------+
|
||
| RAM |
|
||
$8000 +----------+ --
|
||
| |
|
||
| |
|
||
| |
|
||
| RAM | Bank 1
|
||
| |
|
||
| |
|
||
| |
|
||
$4000 +----------+ --
|
||
| |
|
||
| RAM |
|
||
| |
|
||
$2000 +----------+ Bank 0
|
||
| Char ROM |
|
||
$1000 +----------+
|
||
| RAM |
|
||
$0000 +----------+ --
|
||
|
||
|
||
The Char ROM is mapped in at the VIC addresses $1000-$1fff in banks 0 and
|
||
2 (it appears at $9000 in the above diagram, but remember that the VIC
|
||
doesn't know about the two address bits generated by the CIA. From the
|
||
VIC's point of view, the Char ROM is at $1000-$1fff also in bank 2).
|
||
|
||
The attentive reader will already have noticed that the Color RAM doesn't
|
||
seem to appear anywhere. But as explained earlier, the VIC has a 12-bit data
|
||
bus of which the upper 4 bits are connected to the Color RAM. Generally
|
||
speaking, the sole purpose of the upper 4 bits of the VIC data bus is to
|
||
read from the Color RAM. The Color RAM is addressed by the lower 10 bits of
|
||
the VIC address bus and is therefore available in all banks at all
|
||
addresses.
|
||
|
||
2.4.3 Memory access of the 6510 and VIC
|
||
---------------------------------------
|
||
|
||
The VIC only performs read accesses to memory, while the 6510 performs both
|
||
reads and writes. 6510 and VIC are both based on relatively simple
|
||
hard-wired designs, and both chips do a memory access in EVERY clock cycle,
|
||
even if unnecessary. For example, if the processor is busy executing an
|
||
internal operation such as calculating an indexed address, that doesn't
|
||
actually require an access to memory, it nevertheless performs a read access
|
||
and then discards the read byte.
|
||
|
||
There are no wait states, no internal caches and no sophisticated access
|
||
protocols for the bus as seen in more modern computer designs. Every access
|
||
is done in a single cycle.
|
||
|
||
The VIC generates the clock frequencies for the system bus and the RAS and
|
||
CAS signals for accessing the dynamic RAM, for both the processor and the
|
||
VIC itself. It has primary control over the bus and may "stun" the processor
|
||
at times when it needs additional cycles for memory accesses. Additionally,
|
||
the VIC takes care of the DRAM refresh by reading from 5 refresh addresses
|
||
in each raster line.
|
||
|
||
The division of accesses between 6510 and VIC is basically static: Each
|
||
clock cycle (one period of the ϕ2 signal) consists of two phases. The VIC
|
||
accesses in the first phase (ϕ2 low), the processor in the second phase (ϕ2
|
||
high). The AEC signal closely follows ϕ2. That way the 6510 and VIC can
|
||
usually alternate their memory use without disturbing each other.
|
||
|
||
However, the VIC sometimes needs more cycles than it has available via this
|
||
scheme. This is the case when the VIC accesses the character pointers and
|
||
the sprite data. In the first case it needs 40 additional cycles, in the
|
||
second case it needs 2 cycles per sprite. BA will then go low 3 cycles
|
||
before the VIC takes over the bus completely (3 cycles is the maximum number
|
||
of successive write accesses of the 6510). After 3 cycles, AEC stays low
|
||
during the second clock phase so that the VIC can output its addresses.
|
||
|
||
The following diagram illustrates the process of the take-over:
|
||
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
ϕ2 _ _ _ _ _ _ _ _ _ _ _ _ _ ..._ _ _ _ _ _ _ _ _ _ _ _ _
|
||
______________ __________________
|
||
BA ____________...________
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
AEC _ _ _ _ _ _ _ _ _ _ ______..._________ _ _ _ _ _ _ _ _
|
||
|
||
Chip VPVPVPVPVPVPVPVpVpVpVVVVVV...VVVVVVVVVPVPVPVPVPVPVPVP
|
||
|
||
1 | 2 | 3 | 4
|
||
Normal |Take-| VIC has taken | VIC releases
|
||
bus activity |over | over the bus | the bus
|
||
|
||
|
||
The line "Chip" designates which chip is just accessing the bus (as said
|
||
before, there is an access in every cycle). "V" stands for the VIC, "P" for
|
||
the 6510. The cycles designated with "p" are accesses of the 6510 that are
|
||
only performed if they are write accesses, and the first "p" read access
|
||
stops the 6510. On a "p" read access the processor addresses are still
|
||
output on the bus because AEC is still high.
|
||
|
||
The diagram describes the normal process of a bus take-over. By modifying
|
||
VIC register $d011 in certain ways it is possible to force a bus take-over
|
||
at unusual times. This is explained in chapter 3 together with the complete
|
||
bus timing of a VIC raster line.
|
||
|
||
|
||
3. Description of the VIC
|
||
-------------------------
|
||
|
||
This chapter explains the individual function units in the VIC, their way of
|
||
working and their unspecified behavior, and the insights into the internal
|
||
functions of the VIC that can be gained by that.
|
||
|
||
3.1. Block diagram
|
||
------------------
|
||
|
||
The following block diagram gives an overview over the internal structure
|
||
of the VIC and the independently working function units:
|
||
|
||
|
||
IRQ <---------------------------------+
|
||
|
|
||
+---------------+ +-----------------+
|
||
|Refresh counter| | Interrupt logic |<----------------------+
|
||
+---------------+ +-----------------+ |
|
||
+-+ | ^ |
|
||
A |M| v | |
|
||
d |e| +-+ +--------------+ +-------+ |
|
||
d |m| |A| |Raster counter|->| VC/RC | |
|
||
r |o| |d| +->| X/Y | +-------+ |
|
||
. <==>|r| |d| | +--------------+ | |
|
||
+ |y| |r| | | | | | |
|
||
d | | |.|<--------+----------------+ +------------------------+ |
|
||
a |i| |g|===========================>|40×12 bit video matrix-/| |
|
||
t |n|<=>|e| | | | | color line | |
|
||
a |t| |n| | | | +------------------------+ |
|
||
|e| |e| | | | || |
|
||
|r| |r| | | | +----------------+ || |
|
||
BA <--|f| |a|============>|8×24 bit sprite | || |
|
||
|a| |t|<----+ | | | data buffers | || |
|
||
AEC <--|c| |o| | | v | +----------------+ || |
|
||
|e| |r| | +-----+ | || || |
|
||
+-+ +-+ | |MC0-7| | \/ \/ |
|
||
| +-----+ | +--------------+ +--------------+ |
|
||
| | | Sprite data | |Graphics data | |
|
||
+---------------+ | | sequencer | | sequencer | |
|
||
RAS <--| | | +--------------+ +--------------+ |
|
||
CAS <--|Clock generator| | | | |
|
||
ϕ0 <--| | | v v |
|
||
+---------------+ | +-----------------------+ |
|
||
^ | | MUX | |
|
||
| | | Sprite priorities and |-----------+
|
||
ϕIN -----------+ | | collision detection |
|
||
| +-----------------------+
|
||
VC: Video Matrix Counter | |
|
||
| v
|
||
RC: Row Counter | +-------------+
|
||
+----------->| Border unit |
|
||
MC: MOB Data Counter | +-------------+
|
||
| |
|
||
v v
|
||
+----------------+ +----------------+
|
||
|Sync generation | |Color generation|<-------- ϕCOLOR
|
||
+----------------+ +----------------+
|
||
| |
|
||
v v
|
||
Video output
|
||
(S/LUM and COLOR)
|
||
|
||
|
||
The lightpen unit is not shown.
|
||
|
||
As you can see, the "Raster counter X/Y" plays a central role. This is no
|
||
surprise as the complete screen display and all bus accesses are
|
||
synchronized to it.
|
||
|
||
It is important to note that the units for display and for memory access are
|
||
separate from each other for the sprites as well as for the graphics. There
|
||
is a data buffer between the two units that holds the read graphics data and
|
||
buffers it for the display circuits. In the normal operation of the VIC, the
|
||
functions of the two units are so closely tied to each other that they
|
||
appear like a single function block. By appropriate programming, however,
|
||
you can decouple the circuits and, for example, display graphics without
|
||
previously having read data (in this case, the data which is still in the
|
||
buffer is displayed).
|
||
|
||
3.2. Registers
|
||
--------------
|
||
|
||
The VIC has 47 read/write registers for the processor to control its
|
||
functions:
|
||
|
||
#| Adr. |Bit7|Bit6|Bit5|Bit4|Bit3|Bit2|Bit1|Bit0| Function
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
0| $d000 | M0X | X coordinate sprite 0
|
||
--+-------+---------------------------------------+------------------------
|
||
1| $d001 | M0Y | Y coordinate sprite 0
|
||
--+-------+---------------------------------------+------------------------
|
||
2| $d002 | M1X | X coordinate sprite 1
|
||
--+-------+---------------------------------------+------------------------
|
||
3| $d003 | M1Y | Y coordinate sprite 1
|
||
--+-------+---------------------------------------+------------------------
|
||
4| $d004 | M2X | X coordinate sprite 2
|
||
--+-------+---------------------------------------+------------------------
|
||
5| $d005 | M2Y | Y coordinate sprite 2
|
||
--+-------+---------------------------------------+------------------------
|
||
6| $d006 | M3X | X coordinate sprite 3
|
||
--+-------+---------------------------------------+------------------------
|
||
7| $d007 | M3Y | Y coordinate sprite 3
|
||
--+-------+---------------------------------------+------------------------
|
||
8| $d008 | M4X | X coordinate sprite 4
|
||
--+-------+---------------------------------------+------------------------
|
||
9| $d009 | M4Y | Y coordinate sprite 4
|
||
--+-------+---------------------------------------+------------------------
|
||
10| $d00a | M5X | X coordinate sprite 5
|
||
--+-------+---------------------------------------+------------------------
|
||
11| $d00b | M5Y | Y coordinate sprite 5
|
||
--+-------+---------------------------------------+------------------------
|
||
12| $d00c | M6X | X coordinate sprite 6
|
||
--+-------+---------------------------------------+------------------------
|
||
13| $d00d | M6Y | Y coordinate sprite 6
|
||
--+-------+---------------------------------------+------------------------
|
||
14| $d00e | M7X | X coordinate sprite 7
|
||
--+-------+---------------------------------------+------------------------
|
||
15| $d00f | M7Y | Y coordinate sprite 7
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
16| $d010 |M7X8|M6X8|M5X8|M4X8|M3X8|M2X8|M1X8|M0X8| MSBs of X coordinates
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
17| $d011 |RST8| ECM| BMM| DEN|RSEL| YSCROLL | Control register 1
|
||
--+-------+----+----+----+----+----+--------------+------------------------
|
||
18| $d012 | RASTER | Raster counter
|
||
--+-------+---------------------------------------+------------------------
|
||
19| $d013 | LPX | Light pen X
|
||
--+-------+---------------------------------------+------------------------
|
||
20| $d014 | LPY | Light pen Y
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
21| $d015 | M7E| M6E| M5E| M4E| M3E| M2E| M1E| M0E| Sprite enabled
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
22| $d016 | - | - | RES| MCM|CSEL| XSCROLL | Control register 2
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
23| $d017 |M7YE|M6YE|M5YE|M4YE|M3YE|M2YE|M1YE|M0YE| Sprite Y expansion
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
24| $d018 |VM13|VM12|VM11|VM10|CB13|CB12|CB11| - | Memory pointers
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
25| $d019 | IRQ| - | - | - | ILP|IMMC|IMBC|IRST| Interrupt register
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
26| $d01a | - | - | - | - | ELP|EMMC|EMBC|ERST| Interrupt enabled
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
27| $d01b |M7DP|M6DP|M5DP|M4DP|M3DP|M2DP|M1DP|M0DP| Sprite data priority
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
28| $d01c |M7MC|M6MC|M5MC|M4MC|M3MC|M2MC|M1MC|M0MC| Sprite multicolor
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
29| $d01d |M7XE|M6XE|M5XE|M4XE|M3XE|M2XE|M1XE|M0XE| Sprite X expansion
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
30| $d01e | M7M| M6M| M5M| M4M| M3M| M2M| M1M| M0M| Sprite-sprite collision
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
31| $d01f | M7D| M6D| M5D| M4D| M3D| M2D| M1D| M0D| Sprite-data collision
|
||
--+-------+----+----+----+----+----+----+----+----+------------------------
|
||
32| $d020 | - | - | - | - | EC | Border color
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
33| $d021 | - | - | - | - | B0C | Background color 0
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
34| $d022 | - | - | - | - | B1C | Background color 1
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
35| $d023 | - | - | - | - | B2C | Background color 2
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
36| $d024 | - | - | - | - | B3C | Background color 3
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
37| $d025 | - | - | - | - | MM0 | Sprite multicolor 0
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
38| $d026 | - | - | - | - | MM1 | Sprite multicolor 1
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
39| $d027 | - | - | - | - | M0C | Color sprite 0
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
40| $d028 | - | - | - | - | M1C | Color sprite 1
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
41| $d029 | - | - | - | - | M2C | Color sprite 2
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
42| $d02a | - | - | - | - | M3C | Color sprite 3
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
43| $d02b | - | - | - | - | M4C | Color sprite 4
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
44| $d02c | - | - | - | - | M5C | Color sprite 5
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
45| $d02d | - | - | - | - | M6C | Color sprite 6
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
46| $d02e | - | - | - | - | M7C | Color sprite 7
|
||
--+-------+----+----+----+----+-------------------+------------------------
|
||
|
||
Notes:
|
||
|
||
· The bits marked with '-' are not connected and yield "1" on reading.
|
||
· The VIC registers are repeated every 64 bytes in the area $d000-$d3ff,
|
||
i.e. register 0 appears on addresses $d000, $d040, $d080 etc.
|
||
· The unused addresses $d02f-$d03f yield $ff on reading, a write access is
|
||
ignored.
|
||
· The registers $d01e and $d01f cannot be written and are automatically
|
||
cleared on reading.
|
||
· The RES bit (bit 5) of register $d016 has no known function on the VIC
|
||
types 6567/6569. On the 6566, this bit is used to stop the VIC.
|
||
· Bit 7 in register $d011 (RST8) is bit 8 of register $d012. Together they
|
||
are called "RASTER" in the following. A write access to these bits sets
|
||
the comparison line for the raster interrupt (see section 3.12.).
|
||
|
||
3.3. Color palette
|
||
------------------
|
||
|
||
The VIC has a hard-wired palette of 16 colors that are encoded in 4 bits:
|
||
|
||
0 black
|
||
1 white
|
||
2 red
|
||
3 cyan
|
||
4 pink
|
||
5 green
|
||
6 blue
|
||
7 yellow
|
||
8 orange
|
||
9 brown
|
||
10 light red
|
||
11 dark gray
|
||
12 medium gray
|
||
13 light green
|
||
14 light blue
|
||
15 light gray
|
||
|
||
The VIC does not use RGB color generation like modern graphics chips but is
|
||
designed for analog color television, which represents color information as
|
||
the phase shift and amplitude of a sinusoidal signal that is output on the
|
||
COLOR pin of the VIC.
|
||
|
||
Internally, the VIC generates this color signal by mixing a sine and a
|
||
cosine wave, both derived from the ϕCOLOR input of the chip [6]. The
|
||
amplitudes of these two signals are modulated according to the individual
|
||
color value in order to produce the desired phase and amplitude of the
|
||
output signal.
|
||
|
||
There is some difference in the luminance levels generated for each of the
|
||
16 different colors depending on the VIC chip revision. Older revisions
|
||
(6569R1) produced five distinct levels, while newer version increased this
|
||
to nine levels. Presumably this was done to make the colors more
|
||
distinguishable on monochrome displays.
|
||
|
||
See [8] for an in-depth description and reverse engineering of the VIC color
|
||
palette.
|
||
|
||
3.4. Display generation and display window dimensions
|
||
-----------------------------------------------------
|
||
|
||
As usual for controlling CRT displays, the VIC builds up the video frame
|
||
line by line. The line number and the number of clock cycles per line are
|
||
constant for each VIC type. The VIC works character-based, with every
|
||
character consisting of a matrix of 8×8 pixels, so a text line is made up of
|
||
8 pixel lines. 40×25 text characters are displayed in the text based modes,
|
||
and 320×200 or 160×200 pixels in the bitmap modes.
|
||
|
||
In this article, we will specify a position on the screen using the raster
|
||
line number as the Y coordinate (RASTER, register $d011/$d012) and an X
|
||
coordinate that corresponds to the sprite coordinate system. When specifying
|
||
the time of a VIC memory access or an internal operation in the VIC, we will
|
||
use the raster line number as the Y coordinate and the number of the clock
|
||
cycle (and sometimes also the clock phase) within that line as the X
|
||
coordinate. As previously mentioned, 8 pixels make one clock cycle, so the
|
||
specification of a sprite X coordinate is eight times more precise than that
|
||
of a cycle number.
|
||
|
||
The VIC displays its main graphics in an unmovable window in the middle of
|
||
the visible screen area, the "display window". The area outside the display
|
||
window is covered by the screen border and is displayed in the border color
|
||
(EC, register $d020). You can also turn off the border partially or
|
||
completely with some programming tricks (see section 3.9.); then it becomes
|
||
apparent that the display window is part of a "display column" which is the
|
||
linear extension of the display window to the top and bottom. With this you
|
||
can divide the border into an upper/lower border and a left/right border.
|
||
The visible screen area is surrounded by blanking intervals in which the
|
||
video signal is turned off and in which the raster beam returns to the start
|
||
of the next line or the start of the frame, respectively.
|
||
|
||
The following figure (not to scale) illustrates the last paragraph:
|
||
|
||
|
||
Visible pixels/line
|
||
____________________|___________________
|
||
/ \
|
||
|
||
+------------------------------------------------+ <- Raster line 0 (6569)
|
||
| . . |
|
||
| . Vertical blanking interval . |
|
||
| . . |
|
||
+---+---+--------------------------------+---+---+ \
|
||
| | | | | | |
|
||
| H | | Upper border | | H | |
|
||
| o | | | | o | |
|
||
| r | +--------------------------------+ | r | |
|
||
| i | | | | i | |
|
||
| z | | | | z | |
|
||
| o | | | | o | |
|
||
| n | | | | n | |
|
||
| t | | | | t | |
|
||
| a | | | r | a | |
|
||
| l | l | | i | l | |
|
||
| | e | | g | | |
|
||
| b | f | | h | b | |
|
||
| l | t | | t | l | |
|
||
| a | | Display window | | a | |- Visible lines
|
||
| n | b | | b | n | |
|
||
| k | o | | o | k | |
|
||
| i | r | | r | i | |
|
||
| n | d | | d | n | |
|
||
| g | e | | e | g | |
|
||
| | r | | r | | |
|
||
| i | | | | i | |
|
||
| n | | | | n | |
|
||
| t | | | | t | |
|
||
| e | | | | e | |
|
||
| r | | | | r | |
|
||
| v | +--------------------------------+ | v | |
|
||
| a | | | | a | |
|
||
| l | | Lower border | | l | | <- Raster line 0 (6567)
|
||
| | | | | | |
|
||
+---+---+--------------------------------+---+---+ /
|
||
| . . |
|
||
| . Vertical blanking interval . |
|
||
| . . |
|
||
+------------------------------------------------+
|
||
|
||
^ \________________________________/
|
||
| |
|
||
| Display column
|
||
|
|
||
X coordinate 0
|
||
|
||
|
||
The height and width of the display window can be separately set to two
|
||
different values with the bits RSEL and CSEL in the registers $d011 and
|
||
$d016:
|
||
|
||
RSEL| Display window height | First line | Last line
|
||
----+--------------------------+-------------+----------
|
||
0 | 24 text lines/192 pixels | 55 ($37) | 246 ($f6)
|
||
1 | 25 text lines/200 pixels | 51 ($33) | 250 ($fa)
|
||
|
||
CSEL| Display window width | First X coo. | Last X coo.
|
||
----+--------------------------+--------------+------------
|
||
0 | 38 characters/304 pixels | 31 ($1f) | 334 ($14e)
|
||
1 | 40 characters/320 pixels | 24 ($18) | 343 ($157)
|
||
|
||
If RSEL=0 the upper and lower border each grow by 4 pixels into the display
|
||
window. If CSEL=0 the left border grows by 7 pixels and the right one by 9
|
||
pixels. The position of the display window and its resolution do not change:
|
||
RSEL/CSEL only switch the starting and ending position of the border
|
||
display. The size of the video matrix also stays constantly at 40×25
|
||
characters.
|
||
|
||
With XSCROLL (bits 0-2 of register $d016) and YSCROLL (bits 0-2 of register
|
||
$d011) the position of the graphics inside the display window can be shifted
|
||
in single-pixel units up to 7 pixels to the right and to the bottom. This
|
||
can be used for soft scrolling. The position of the display window itself
|
||
doesn't change. To align the graphics with the window, X/YSCROLL have to be
|
||
set to 0 and 3 for 25 lines/40 columns, and to 7 each for 24 lines/38
|
||
columns.
|
||
|
||
The dimensions of the video display for the different VIC types are as
|
||
follows:
|
||
|
||
| Video | # of | Visible | Cycles/ | Visible
|
||
Type | system | lines | lines | line | pixels/line
|
||
---------+--------+-------+---------+---------+------------
|
||
6567R56A | NTSC-M | 262 | 234 | 64 | 411
|
||
6567R8 | NTSC-M | 263 | 235 | 65 | 418
|
||
6569 | PAL-B | 312 | 284 | 63 | 403
|
||
|
||
| First | Last | | First | Last
|
||
| vblank | vblank | First X coo. | visible | visible
|
||
Type | line | line | of a line | X coo. | X coo.
|
||
---------+--------+--------+--------------+------------+-----------
|
||
6567R56A | 13 | 40 | 412 ($19c) | 488 ($1e8) | 388 ($184)
|
||
6567R8 | 13 | 40 | 412 ($19c) | 489 ($1e9) | 396 ($18c)
|
||
6569 | 300 | 15 | 404 ($194) | 480 ($1e0) | 380 ($17c)
|
||
|
||
If you are wondering why the first visible X coordinates seem to come after
|
||
the last visible ones: This is because as the reference point that marks the
|
||
beginning of a raster line, we have chosen the occurrence of the raster IRQ
|
||
which doesn't coincide with X coordinate 0 but with the coordinate given as
|
||
"First X coo. of a line". The X coordinates run up to $1ff (only $1f7 on the
|
||
6569) within a line, then follows X coordinate 0. This is explained in more
|
||
detail in the explanation of the structure of a raster line.
|
||
|
||
3.5. Bad Lines
|
||
--------------
|
||
|
||
As already mentioned, the VIC needs 40 additional bus cycles when fetching
|
||
the character pointers (i.e. the character codes of one text line from the
|
||
video matrix), because the 63-65 bus cycles available for transparent access
|
||
by the VIC during the first clock phases within a line are not sufficient to
|
||
read both the character pointers and the pixel data for the characters from
|
||
memory.
|
||
|
||
For this reason, the VIC uses the mechanism described in section 2.4.3. to
|
||
"stun" the processor for 40-43 cycles during the first pixel line of each
|
||
text line to read the character pointers. The raster lines in which this
|
||
happens are usually called "Bad Lines" ("bad" because they stop the
|
||
processor and thus slow down the computer and lead to problems if the
|
||
precise timing of a program is essential, e.g. for the transmission of data
|
||
to/from a floppy drive).
|
||
|
||
The character pointer access also happens in the bitmap modes, because the
|
||
video matrix data is then used for color information.
|
||
|
||
Normally, every eighth line inside the display window, starting with the
|
||
very first line of the graphics, is a Bad Line, i.e. the first raster line
|
||
of each text line. So the position of the Bad Lines depends on the YSCROLL.
|
||
As you will see later, the entire graphics display and memory access scheme
|
||
depend completely on the position of the Bad Lines.
|
||
|
||
It is therefore necessary to introduce a more general definition, namely
|
||
that of a "Bad Line Condition":
|
||
|
||
A Bad Line Condition is given at any arbitrary clock cycle if, at the
|
||
negative edge of ϕ0 at the beginning of the cycle, RASTER >= $30 and RASTER
|
||
<= $f7 and the lower three bits of RASTER are equal to YSCROLL, and if the
|
||
DEN bit was set during an arbitrary cycle of raster line $30.
|
||
|
||
This definition has to be taken literally. You can produce or cancel a Bad
|
||
Line Condition multiple times within an arbitrary raster line in the range
|
||
of $30-$f7 by modifying YSCROLL, and thus make every raster line within the
|
||
display window completely or partially a Bad Line, or trigger or suppress
|
||
all the other functions that are connected with a Bad Line Condition. If
|
||
YSCROLL=0, a Bad Line Condition occurs in raster line $30 as soon as the DEN
|
||
bit (register $d011, bit 4) is set (for more about the DEN bit, see section
|
||
3.10.).
|
||
|
||
The following three sections describe the function units that are used for
|
||
displaying the graphics. Section 3.6. explains the the memory interface used
|
||
to read the graphics data and the timing of the accesses within a raster
|
||
line. Section 3.7. is about the display unit that converts the text and
|
||
bitmap graphics data into colors and generates the addresses for the memory
|
||
access. Section 3.8. covers the sprites and their address generation.
|
||
|
||
3.6. Memory access
|
||
------------------
|
||
|
||
3.6.1. The X coordinates
|
||
------------------------
|
||
|
||
Before explaining the timing of memory accesses within a raster line, we
|
||
will quickly explain how to obtain the X coordinates. This is necessary
|
||
because the VIC doesn't have a counterpart to the RASTER register that holds
|
||
the current X coordinate, so you cannot simply read it with the processor.
|
||
But the VIC surely keeps track of the X coordinates internally as the
|
||
horizontal sprite positions are based on them, and a pulse at the lightpen
|
||
input LP latches the current X position in the register LPX ($d013).
|
||
|
||
Determining the absolute X coordinates of events within a raster line is not
|
||
trivial as you cannot e.g. simply put a sprite to a well-defined X
|
||
coordinate and derive from the text characters displayed at the same X
|
||
position the X coordinates of the memory accesses belonging to these
|
||
characters. The memory access and the display are separate function units
|
||
and the read graphics data is not immediately displayed on the screen (there
|
||
is in fact a delay of 12 pixels).
|
||
|
||
So we have taken a different approach: The absolute position of a single X
|
||
coordinate within the raster line was measured with the LPX register and the
|
||
other X coordinates were determined relative to this. To do that, the IRQ
|
||
output of the VIC has been connected to the LP input and the VIC has been
|
||
programmed for a raster line interrupt. As the negative edge of IRQ was
|
||
defined to be the start of a raster line, the absolute X position of the
|
||
line start could be determined in this way. The position of the negative
|
||
edge of BA during a Bad Line was also measured with this method and the
|
||
result was consistent with the relative distance of IRQ and BA to each
|
||
other. Based on these two measurements, the X coordinates of all other
|
||
events within a raster line have been determined (see [4]). Only now could
|
||
the sprite X coordinates be used to determine the moment of the display
|
||
generation of the text characters.
|
||
|
||
This of course implicitly assumes that the LPX coordinates are the same as
|
||
the sprite X coordinates. There is, however, no indication and thus no
|
||
reason to suppose that they aren't (a direct correlation would also be the
|
||
most simple solution in terms of circuit design).
|
||
|
||
3.6.2. Access types
|
||
-------------------
|
||
|
||
The VIC generates two kinds of graphics that require access to memory: The
|
||
text/bitmap graphics (also often called "background graphics" or simply
|
||
"graphics") and the sprite graphics. Both require accesses to two separate
|
||
memory areas:
|
||
|
||
For the text/bitmap graphics:
|
||
|
||
· The video matrix, an area of 1000 video addresses (40×25, 12 bits each)
|
||
that can be moved in 1KB steps within the 16KB address space of the VIC
|
||
with the bits VM10-VM13 of register $d018. It stores the character codes
|
||
and their color for the text modes and some of the color information of
|
||
8×8 pixel blocks for the bitmap modes. The Color RAM is part of the video
|
||
matrix and delivers the upper 4 bits of the 12-bit matrix. The data read
|
||
from the video matrix is stored in an internal buffer in the VIC, the
|
||
40×12 bit video matrix/color line.
|
||
|
||
· The character generator or, respectively, the bitmap: an area of 2048
|
||
bytes (bitmap: 8000 bytes) that can be moved in 2KB steps (bitmap: 8KB
|
||
steps) within the VIC address space with the bits CB11-CB13 (bitmap: only
|
||
CB13) of register $d018. It stores the pixel data of the characters for
|
||
the text modes and the bitmap for the bitmap modes. The character
|
||
generator is not to be confused with the Char ROM. The Char ROM contains
|
||
prepared bit patterns that can be used as a character generator, but you
|
||
can also put the character generator in normal RAM to define your own
|
||
character images.
|
||
|
||
For the sprites:
|
||
|
||
· The sprite data pointers: 8 bytes after the end of the video matrix,
|
||
that select one out of 256 blocks of 64 bytes within the VIC address
|
||
space for each sprite.
|
||
|
||
· The sprite data: an area of 63 bytes containing the pixel data of the
|
||
sprites which can be moved in steps of 64 bytes with the sprite data
|
||
pointers, independently for each sprite.
|
||
|
||
Corresponding to these memory areas, the VIC performs 4 different kinds of
|
||
graphics accesses:
|
||
|
||
1. To the video matrix ("c-access", 12 bits wide).
|
||
|
||
2. To the pixel data, i.e. character generator or bitmap ("g-access", 8
|
||
bits wide).
|
||
|
||
3. To the sprite data pointers ("p-access", 8 bits wide).
|
||
|
||
4. To the sprite data ("s-access", 8 bits wide).
|
||
|
||
Moreover, the VIC does two additional types of accesses:
|
||
|
||
5. Accesses for refreshing the dynamic RAM: 5 read accesses per raster
|
||
line.
|
||
|
||
6. Idle accesses. As described, the VIC accesses memory in every first clock
|
||
phase although there are some cycles in which no other of the above
|
||
mentioned accesses is pending. In this case, the VIC does an idle access:
|
||
a read access to video address $3fff (i.e. to $3fff, $7fff, $bfff or
|
||
$ffff depending on the VIC bank), the result of which is discarded.
|
||
|
||
3.6.3. Timing of a raster line
|
||
------------------------------
|
||
|
||
The sequence of VIC memory accesses within a raster line is hard-wired,
|
||
independent of the graphics mode and the same for every raster line. The
|
||
negative edge of IRQ on a raster interrupt has been used to define the
|
||
beginning of a line (this is also the moment in which the RASTER register
|
||
is incremented). Raster line 0 is, however, an exception: In this line, IRQ
|
||
and incrementing (resp. resetting) of RASTER are performed one cycle later
|
||
than in the other lines. But for simplicity we assume equal line lengths
|
||
and define the beginning of raster line 0 to be one cycle before the
|
||
occurrence of the IRQ.
|
||
|
||
First the timing diagrams, the explanation will follow below:
|
||
|
||
|
||
6569, Bad Line, no sprites:
|
||
|
||
Cycl-# 6 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6
|
||
3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 1
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
__
|
||
IRQ ________________________________________________________________________________________________________________________________
|
||
________________________ ____________________
|
||
BA ______________________________________________________________________________________
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
AEC _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _________________________________________________________________________________ _ _ _ _ _ _ _ _ _
|
||
|
||
VIC i 3 i 4 i 5 i 6 i 7 i r r r r rcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcgcg i i 0 i 1 i 2 i 3
|
||
6510 x x x x x x x x x x x x X X X x x x x x x x x x x
|
||
|
||
Graph. |===========01020304050607080910111213141516171819202122232425262728293031323334353637383940=========
|
||
|
||
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
1111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111
|
||
89999aaaabbbbccccddddeeeeff0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff000011112222333344445555666677778888999
|
||
c048c048c048c048c048c048c04048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048
|
||
|
||
|
||
6569, no Bad Line, no sprites (shortened):
|
||
|
||
Cycl-# 6 1 1 1 1 1 1 1 1 1 1 |5 5 5 5 5 5 5 6 6 6 6
|
||
3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |3 4 5 6 7 8 9 0 1 2 3 1
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _
|
||
ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _
|
||
__ |
|
||
IRQ ______________________________________|________________________
|
||
________________________________________|________________________
|
||
BA |
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _
|
||
AEC _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _
|
||
|
|
||
VIC i 3 i 4 i 5 i 6 i 7 i r r r r r g g g g |g g g i i 0 i 1 i 2 i 3
|
||
6510 x x x x x x x x x x x x x x x x x x x x| x x x x x x x x x x x x
|
||
|
|
||
Graph. |===========0102030|7383940=========
|
||
|
|
||
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|\\\\\\\\\\\\\\\\\\\\\\\\
|
||
1111111111111111111111111110000000000000|111111111111111111111111
|
||
89999aaaabbbbccccddddeeeeff0000111122223|344445555666677778888999
|
||
c048c048c048c048c048c048c04048c048c048c0|c048c048c048c048c048c048
|
||
|
||
|
||
6567R56A, Bad Line, sprites 5-7 active in this line, sprite 0 in the next
|
||
line (shortened):
|
||
|
||
Cycl-# 6 1 1 1 1 1 1 1 1 1 1 |5 5 5 5 5 5 5 6 6 6 6 6
|
||
4 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |3 4 5 6 7 8 9 0 1 2 3 4 1
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _
|
||
__ |
|
||
IRQ ______________________________________|__________________________
|
||
____ __ | __ __________
|
||
BA __________________ ________________|____ __________
|
||
_ _ _ _ _ _ _ _ _ | _ _ _ _ _ _ _ _ _
|
||
AEC _ _ _ _ _ _____________ _ _ _ __________|_____ _ _ _ _____ _ _ _ _
|
||
|
|
||
VIC i 3 i 4 i 5sss6sss7sssr r r r rcgcgcgcgc|gcgcg i i i 0sss1 i 2 i 3
|
||
6510 x x X X X x X X X | x X X X x x x x x
|
||
|
|
||
Graph. |===========0102030|7383940===========
|
||
|
|
||
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
1111111111111111111111111110000000000000|11111111111111111111111111
|
||
999aaaabbbbccccddddeeeeffff0000111122223|3444455556666777788889999a
|
||
48c048c048c048c048c048c048c048c048c048c0|c048c048c048c048c048c048c0
|
||
|
||
|
||
6567R8, no Bad Line, sprites 2-7 active in this line, sprites 0-4 in the
|
||
next line (shortened):
|
||
|
||
Cycl-# 6 1 1 1 1 1 1 1 1 1 1 |5 5 5 5 5 5 5 6 6 6 6 6 6
|
||
5 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |3 4 5 6 7 8 9 0 1 2 3 4 5 1
|
||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
ϕ0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||
__ |
|
||
IRQ ______________________________________|____________________________
|
||
__________________|________
|
||
BA ______________________ | ____________________
|
||
_ _ _ _ _ _ _ _ _| _ _ _ _ _ _ _
|
||
AEC _______________________ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ ______________
|
||
|
|
||
VIC ss3sss4sss5sss6sss7sssr r r r r g g g g |g g g i i i i 0sss1sss2sss3s
|
||
6510 x x x x x x x x x| x x x x X X X
|
||
|
|
||
Graph. |===========0102030|7383940============
|
||
|
|
||
X coo. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|\\\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
1111111111111111111111111110000000000000|1111111111111111111111111111
|
||
999aaaabbbbccccddddeeeeffff0000111122223|344445555666677778888889999a
|
||
48c048c048c048c048c048c048c048c048c048c0|c048c048c048c048c04cccc048c0
|
||
|
||
|
||
The line "Cycl-#" shows the number of the clock cycle within the raster
|
||
line. The line starts with cycle 1 and consists of 63 cycles on the 6569,
|
||
64 cycles on the 6567R56A, and 65 cycles on the 6567R8. The last cycle of
|
||
the previous line and the first cycle of the next line have also been
|
||
included in the diagrams to make things clearer.
|
||
|
||
The lines "ϕ0", "IRQ", "BA" and "AEC" reflect the state of the respective
|
||
bus signals. ϕ0 is low in the first phase and high in the second phase.
|
||
|
||
The symbols in the lines "VIC" and "6510" show what kind of access VIC and
|
||
6510 do in the corresponding clock phase (for an explanation of the
|
||
different access types of the VIC see section 3.6.2.):
|
||
|
||
c Reading the video matrix and Color RAM (c-access)
|
||
g Reading the character generator or bitmap (g-access)
|
||
0-7 Reading the sprite data pointer for sprite 0-7 (p-access)
|
||
s Reading the sprite data (s-access)
|
||
r DRAM refresh
|
||
i Idle access
|
||
|
||
x Read or write access of the processor
|
||
X Processor may do write accesses, stops on first read (BA is low and so
|
||
is RDY)
|
||
|
||
The line "X coo." contains the X coordinates of the beginning of each clock
|
||
phase (thus the "\\\" as a reminder) and the line "Graph." is a projection
|
||
of the 40 column display window and the border to these coordinates, for
|
||
positioning sprites. However, this doesn't correspond to the signal on the
|
||
VIC video output. Also the "Graph." line doesn't show when the border unit
|
||
generates the border. This happens approx. 8 pixels later than shown in the
|
||
"Graph." line.
|
||
|
||
To time the accesses of the processor within a raster line when programming,
|
||
it's best to use the VIC g-accesses for orientation by changing a byte in
|
||
graphics memory with the 6510 and watching on the screen for which character
|
||
the change is first visible. The write access of the processor must then
|
||
have occurred in the clock phase immediately before. Then you can use the
|
||
diagrams to determine the clock cycle in which the access took place and
|
||
count the other accesses relative to it.
|
||
|
||
3.7. Text/bitmap display
|
||
------------------------
|
||
|
||
3.7.1. Idle state / display state
|
||
---------------------------------
|
||
|
||
The text/bitmap display logic in the VIC is in one of two states at any
|
||
time: the idle state or the display state.
|
||
|
||
- In display state, c- and g-accesses take place, with the addresses and
|
||
interpretation of the data depending on the selected display mode.
|
||
|
||
- In idle state, only g-accesses occur. The access is always to address
|
||
$3fff ($39ff when the ECM bit in register $d016 is set). The graphics
|
||
are displayed by the sequencer exactly as in display state, but with
|
||
the video matrix data treated as "0" bits.
|
||
|
||
The transition from idle to display state occurs as soon as there is a Bad
|
||
Line Condition (see section 3.5.). The transition from display to idle
|
||
state occurs in cycle 58 of a line if the RC (see next section) contains
|
||
the value 7 and there is no Bad Line Condition.
|
||
|
||
As long as register $d011 is not modified in the middle of a frame, the
|
||
display logic is in display state within the display window and in idle
|
||
state outside of it. If you set a YSCROLL other than 3 in a 25 line display
|
||
window and store a value other than zero in $3fff you can see the black
|
||
stripes generated by the sequencer in idle state on the upper or lower edge
|
||
of the window.
|
||
|
||
In [4], idle accesses as well as g-accesses in idle state are called "idle
|
||
bus cycle", but the two phenomena are not the same. The accesses marked
|
||
with "+" in the diagrams of [4] are normal g-accesses. In this article, the
|
||
term "idle access" is only used for the accesses marked with "i" in the
|
||
diagrams in section 3.6.3., and not for the g-accesses during idle state.
|
||
|
||
3.7.2. VC and RC
|
||
----------------
|
||
|
||
Probably the most important result of the VIC examinations is the discovery
|
||
of the function of the internal registers "VC" and "RC" of the VIC. These
|
||
are used to generate the addresses for accessing the video matrix and the
|
||
character generator/bitmap.
|
||
|
||
Strictly speaking there are three registers:
|
||
|
||
· "VC" (video counter) is a 10-bit counter that can be loaded with the
|
||
value from VCBASE.
|
||
· "VCBASE" (video counter base) is a 10-bit data register with reset input
|
||
that can be loaded with the value from VC.
|
||
· "RC" (row counter) is a 3-bit counter with reset input.
|
||
|
||
Apart from these, there is a mechanism in the VIC which keeps track of the
|
||
position within the internal 40×12 bit video matrix/color line where read
|
||
character pointers are stored or read back from again, respectively. We will
|
||
call this the "VMLI" (video matrix line index) here.
|
||
|
||
On the VIC, the VMLI is actually implemented as a 40-bit shift register
|
||
which under normal circumstances shifts along a single "1" bit that
|
||
addresses exactly one cell of the video matrix line. To start this sequence
|
||
in display state, a new "1" bit is shifted in at the input, and in idle
|
||
state the register has run empty. This may be the reason why idle state
|
||
graphics (see section 3.7.3.9.) are black - there is no color information
|
||
coming in from the video matrix line.
|
||
|
||
With programming tricks (see section 3.14.6.) is it possible to manipulate
|
||
the shift register to contain more than one set bit, causing more than one
|
||
memory cell to be addressed at the same time. This usually leads to highly
|
||
unstable behavior and mixing of character and color data which varies among
|
||
VIC chip revisions and can also depend on factors such as the chip
|
||
temperature. As these effects are not of any known practical use on the C64,
|
||
we will in the following simplify the description of the VMLI by treating it
|
||
as an ordinary 6-bit counter with a reset input.
|
||
|
||
These four registers behave according to the following rules:
|
||
|
||
1. Once somewhere outside of the range of raster lines $30-$f7 (i.e.
|
||
outside of the Bad Line range), VCBASE is reset to zero. This is
|
||
presumably done in raster line 0; the exact moment cannot be determined
|
||
and is irrelevant.
|
||
|
||
2. In the first phase of cycle 14 of each line, VC is loaded from VCBASE
|
||
(VCBASE->VC) and VMLI is cleared. If there is a Bad Line Condition in
|
||
this phase, RC is also reset to zero.
|
||
|
||
3. If there is a Bad Line Condition in cycles 12-54, BA is set low and the
|
||
c-accesses are started. Once started, one c-access is done in the second
|
||
phase of every clock cycle in the range 15-54. The read data is stored in
|
||
the video matrix/color line at the position specified by VMLI. This data
|
||
is then also internally read from the position specified by VMLI on each
|
||
g-access in display state.
|
||
|
||
4. VC and VMLI are incremented after each g-access in display state.
|
||
|
||
5. In the first phase of cycle 58, the VIC checks if RC=7. If so, the video
|
||
logic goes to idle state and VCBASE is loaded from VC (VC->VCBASE). If
|
||
the video logic is still in display state (which is always the case if
|
||
there is a Bad Line Condition), then RC is incremented.
|
||
|
||
These rules normally make VC count all 1000 addresses of the video matrix
|
||
within the display frame, and RC count the 8 pixel lines of each text line.
|
||
But this behavior of VC and RC is largely determined by Bad Line Conditions
|
||
which you can affect with the processor via YSCROLL, giving you more control
|
||
over VC and RC within certain limits.
|
||
|
||
3.7.3 Graphics modes
|
||
--------------------
|
||
|
||
The graphics data sequencer provides eight different graphics modes that are
|
||
selected by the bits ECM (Extended Color Mode), BMM (Bit Map Mode) and MCM
|
||
(Multi Color Mode) in the registers $d011 and $d016. Of the eight possible
|
||
bit combinations, three are "invalid" and generate the same output: the
|
||
color black. The idle state is a bit special in that no c-accesses occur in
|
||
it and the sequencer uses "0" bits for the video matrix data.
|
||
|
||
The sequencer outputs the graphics data in every raster line in the area of
|
||
the display column as long as the vertical border flip-flop is reset (see
|
||
section 3.9.). Outside of the display column and if the flip-flop is set,
|
||
the last current background color is displayed (this area is normally
|
||
covered by the border). The heart of the sequencer is an 8-bit shift
|
||
register that is shifted by 1 bit for every pixel, and reloaded with new
|
||
graphics data after each g-access. With XSCROLL from register $d016 the
|
||
reloading can be delayed by 0-7 pixels, thus shifting the display up to 7
|
||
pixels to the right. If XSCROLL is increased in the middle of a line, the
|
||
sequencer produces additional background color pixels. If it is decreased,
|
||
the display of the next set of 8 pixels starts early, aborting the currently
|
||
displayed character.
|
||
|
||
The address generator for the text/bitmap accesses (c- and g-accesses)
|
||
basically has three modes for the g-accesses, while the c-accesses always
|
||
follow the same address scheme. In display state, the BMM bit selects either
|
||
character generator accesses (BMM=0) or bitmap accesses (BMM=1). In idle
|
||
state, the g-accesses are always done at video address $3fff. If the ECM bit
|
||
is set, the address generator always holds the address lines 9 and 10 low
|
||
without any other changes to the addressing scheme (e.g. the g-accesses in
|
||
idle state then occur at address $39ff).
|
||
|
||
In the next sections we will cover the eight graphics modes separately, and
|
||
describe the generated addresses and the interpretation of the read data on
|
||
c- and g-accesses. This is followed by a description of the peculiarities of
|
||
the idle state. For easy reference, the addresses are always given
|
||
explicitly for each mode although, for example, the c-accesses are always
|
||
identical.
|
||
|
||
3.7.3.1. Standard text mode (ECM/BMM/MCM=0/0/0)
|
||
-----------------------------------------------
|
||
|
||
In this mode (as in all text modes), the VIC reads 8-bit character pointers
|
||
from the video matrix that specify the address of the dot matrix of the
|
||
character within the character generator. A character set of 256 characters
|
||
is available, each consisting of 8×8 pixels which are stored in 8 successive
|
||
bytes in the character generator. Both video matrix and character generator
|
||
can be moved in memory with the bits VM10-VM13 and CB11-CB13 of register
|
||
$d018.
|
||
|
||
In standard text mode, each bit in the character generator directly
|
||
corresponds to one pixel on the screen. The foreground color is given by the
|
||
color nybble from the video matrix for each character, the background color
|
||
is set globally with register $d021.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| Color of | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||
| "1" pixels | | | | | | | | |
|
||
+-------------------+----+----+----+----+----+----+----+----+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13|CB12|CB11| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| |
|
||
| "0": Background color 0 ($d021) |
|
||
| "1": Color from bits 8-11 of c-data |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.2. Multicolor text mode (ECM/BMM/MCM=0/0/1)
|
||
-------------------------------------------------
|
||
|
||
This mode allows displaying four-colored characters at the expense of
|
||
horizontal resolution. If bit 11 of the c-data is zero, the character is
|
||
displayed as in standard text mode with only the colors 0-7 available for
|
||
the foreground. If bit 11 is set, two adjacent bits each of the dot matrix
|
||
form one pixel. In this way, the resolution of a character is effectively
|
||
reduced to 4×8 pixels, with each pixel being twice as wide so the total
|
||
width of the characters remains the same.
|
||
|
||
It is interesting to note that not only the bit combination "00" but also
|
||
"01" is regarded as "background" for the purposes of sprite priority and
|
||
collision detection.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| MC | Color of | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||
|flag| "11" pixels | | | | | | | | |
|
||
+----+--------------+----+----+----+----+----+----+----+----+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13|CB12|CB11| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| | MC flag = 0
|
||
| "0": Background color 0 ($d021) |
|
||
| "1": Color from bits 8-10 of c-data |
|
||
+---------------------------------------+
|
||
| 4 pixels (2 bits/pixel) |
|
||
| |
|
||
| "00": Background color 0 ($d021) | MC flag = 1
|
||
| "01": Background color 1 ($d022) |
|
||
| "10": Background color 2 ($d023) |
|
||
| "11": Color from bits 8-10 of c-data |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.3. Standard bitmap mode (ECM/BMM/MCM=0/1/0)
|
||
-------------------------------------------------
|
||
|
||
In this mode, the VIC reads the graphics data from a 320×200 pixel bitmap in
|
||
which each bit corresponds to one pixel on the screen. The data from the
|
||
video matrix is used for color information. As the video matrix is still
|
||
only a 40×25 matrix, you can only specify the colors for blocks of 8×8
|
||
pixels individually (sort of a YC 8:1 format). As the designers of the VIC
|
||
wanted to realize the bitmap mode with as little additional circuitry as
|
||
possible (the VIC-I didn't have a bitmap mode), the arrangement of the
|
||
bitmap in memory is somewhat weird: In contrast to modern video chips that
|
||
read the bitmap in a linear fashion from memory, the VIC forms an 8×8 pixel
|
||
block on the screen from 8 successive bytes of the bitmap. The video matrix
|
||
and the bitmap can be moved in memory with the bits VM10-VM13 and CB13 of
|
||
register $d018.
|
||
|
||
In standard bitmap mode, each bit in the bitmap directly corresponds to one
|
||
pixel on the screen. Foreground and background color can be arbitrarily set
|
||
for each 8×8 pixel block.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| unused | Color of | Color of |
|
||
| | "1" pixels | "0" pixels |
|
||
+-------------------+-------------------+-------------------+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| |
|
||
| "0": Color from bits 0-3 of c-data |
|
||
| "1": Color from bits 4-7 of c-data |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.4. Multicolor bitmap mode (ECM/BMM/MCM=0/1/1)
|
||
---------------------------------------------------
|
||
|
||
Similar to the multicolor text mode, this mode also forms (twice as wide)
|
||
pixels by combining two adjacent bits each. So the resolution is reduced to
|
||
160×200 pixels.
|
||
|
||
The bit combination "01" is also treated as "background" for the sprite
|
||
priority and collision detection, as in multicolor text mode.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| Color of | Color of | Color of |
|
||
| "11 pixels" | "01" pixels | "10" pixels |
|
||
+-------------------+-------------------+-------------------+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 4 pixels (2 bits/pixel) |
|
||
| |
|
||
| "00": Background color 0 ($d021) |
|
||
| "01": Color from bits 4-7 of c-data |
|
||
| "10": Color from bits 0-3 of c-data |
|
||
| "11": Color from bits 8-11 of c-data |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.5. ECM text mode (ECM/BMM/MCM=1/0/0)
|
||
------------------------------------------
|
||
|
||
This text mode is the same as the standard text mode, but it allows the
|
||
selection of one of four background colors for every single character. The
|
||
selection is made with the upper two bits of the character pointer. This,
|
||
however, reduces the available character set from 256 to 64 characters.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| Color of |Back.col.| D5 | D4 | D3 | D2 | D1 | D0 |
|
||
| "1" pixels |selection| | | | | | |
|
||
+-------------------+---------+----+----+----+----+----+----+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13|CB12|CB11| 0 | 0 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| |
|
||
| "0": Depending on bits 6/7 of c-data |
|
||
| 00: Background color 0 ($d021) |
|
||
| 01: Background color 1 ($d022) |
|
||
| 10: Background color 2 ($d023) |
|
||
| 11: Background color 3 ($d024) |
|
||
| "1": Color from bits 8-11 of c-data |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.6. Invalid text mode (ECM/BMM/MCM=1/0/1)
|
||
----------------------------------------------
|
||
|
||
Setting the ECM and MCM bits simultaneously doesn't select one of the
|
||
"official" graphics modes of the VIC but creates only black pixels.
|
||
Nevertheless, the graphics data sequencer internally generates valid
|
||
graphics data that can trigger sprite collisions even in this mode. By using
|
||
sprite collisions you can also read out the generated data (but you cannot
|
||
see anything; the screen is black). You can, however, only distinguish
|
||
foreground and background pixels as you cannot get color information from
|
||
sprite collisions.
|
||
|
||
The generated graphics is similar to that of the multicolor text mode, but
|
||
the character set is limited to 64 characters as in ECM mode.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| MC | unused | D5 | D4 | D3 | D2 | D1 | D0 |
|
||
|flag| | | | | | | |
|
||
+----+------------------------+----+----+----+----+----+----+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13|CB12|CB11| 0 | 0 | D5 | D4 | D3 | D2 | D1 | D0 | RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| | MC flag = 0
|
||
| "0": Black (background) |
|
||
| "1": Black (foreground) |
|
||
+---------------------------------------+
|
||
| 4 pixels (2 bits/pixel) |
|
||
| |
|
||
| "00": Black (background) | MC flag = 1
|
||
| "01": Black (background) |
|
||
| "10": Black (foreground) |
|
||
| "11": Black (foreground) |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.7. Invalid bitmap mode 1 (ECM/BMM/MCM=1/1/0)
|
||
--------------------------------------------------
|
||
|
||
This mode also only displays a black screen, but the pixels can still be
|
||
read out with the sprite collision trick.
|
||
|
||
The structure of the graphics is basically as in standard bitmap mode, but
|
||
the bits 9 and 10 of the g-addresses are always zero due to the set ECM bit
|
||
and so the graphics are, roughly said, made up of four "sections" each of
|
||
which is repeated four times.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| unused |
|
||
+-----------------------------------------------------------+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13| VC9| VC8| 0 | 0 | VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| |
|
||
| "0": Black (background) |
|
||
| "1": Black (foreground) |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.8. Invalid bitmap mode 2 (ECM/BMM/MCM=1/1/1)
|
||
--------------------------------------------------
|
||
|
||
The last invalid mode also creates a black screen that can be "scanned" with
|
||
sprite-graphics collisions.
|
||
|
||
The structure of the graphics is basically as in multicolor bitmap mode, but
|
||
the bits 9 and 10 of the g-addresses are always zero due to the set ECM bit,
|
||
with the same results as in the first invalid bitmap mode. As usual, the bit
|
||
combination "01" is part of the background.
|
||
|
||
c-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| VC9| VC8| VC7| VC6| VC5| VC4| VC3| VC2| VC1| VC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| unused |
|
||
+-----------------------------------------------------------+
|
||
|
||
g-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|CB13| VC9| VC8| 0 | 0 | VC5| VC4| VC3| VC2| VC1| VC0| RC2| RC1| RC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 4 pixels (2 bits/pixel) |
|
||
| |
|
||
| "00": Black (background) |
|
||
| "01": Black (background) |
|
||
| "10": Black (foreground) |
|
||
| "11": Black (foreground) |
|
||
+---------------------------------------+
|
||
|
||
3.7.3.9. Idle state
|
||
-------------------
|
||
|
||
In idle state, the VIC reads the graphics data from address $3fff ($39ff if
|
||
the ECM bit is set) and displays it in the selected graphics mode, but with
|
||
the video matrix data, normally read in the c-accesses, being all "0" bits.
|
||
So the byte at address $3fff/$39ff is output repeatedly.
|
||
|
||
c-access
|
||
|
||
No c-accesses occur.
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
g-access
|
||
|
||
Addresses (ECM=0)
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Addresses (ECM=1)
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) | Standard text mode/
|
||
| | Multicolor text mode/
|
||
| "0": Background color 0 ($d021) | ECM text mode
|
||
| "1": Black |
|
||
+---------------------------------------+
|
||
| 8 pixels (1 bit/pixel) | Standard bitmap mode/
|
||
| | Invalid text mode/
|
||
| "0": Black (background) | Invalid bitmap mode 1
|
||
| "1": Black (foreground) |
|
||
+---------------------------------------+
|
||
| 4 pixels (2 bits/pixel) | Multicolor bitmap mode
|
||
| |
|
||
| "00": Background color 0 ($d021) |
|
||
| "01": Black (background) |
|
||
| "10": Black (foreground) |
|
||
| "11": Black (foreground) |
|
||
+---------------------------------------+
|
||
| 4 pixels (2 bits/pixel) | Invalid bitmap mode 2
|
||
| |
|
||
| "00": Black (background) |
|
||
| "01": Black (background) |
|
||
| "10": Black (foreground) |
|
||
| "11": Black (foreground) |
|
||
+---------------------------------------+
|
||
|
||
3.8. Sprites
|
||
------------
|
||
|
||
Apart from the text/bitmap graphics, the VIC can display eight independent,
|
||
24×21 pixels large, freely movable objects, the "sprites" (called "MOBs"
|
||
(Movable Object Blocks) in [2]).
|
||
|
||
The sprites can have arbitrary positions on the screen, you can switch each
|
||
of them on and off with the bits of register $d015 (MxE), expand them by the
|
||
factor 2 in X and/or Y direction with registers $d017/$d01d (with their
|
||
resolution still being 24×21 pixels), choose between standard and multicolor
|
||
mode with register $d01c (MxMC), set the display priority with respect to
|
||
the text/bitmap graphics with register $d01b (MxDP) and assign a different
|
||
color to each sprite (registers $d027-$d02e). The VIC also has the ability
|
||
to detect collisions between sprites among themselves or between sprites and
|
||
text/bitmap graphics, and to trigger an interrupt on such collisions (see
|
||
section 3.12.).
|
||
|
||
The position of the top left corner of a sprite is specified via its
|
||
respective coordinate registers (MxX, MxY). There are 8 bits for the Y
|
||
coordinate and 9 bits for the X coordinate (the most significant bits of the
|
||
X coordinates of all sprites are collected in register $d010).
|
||
|
||
3.8.1. Memory access and display
|
||
--------------------------------
|
||
|
||
The 63 bytes of sprite data necessary for displaying 24×21 pixels are
|
||
stored in memory in a linear fashion: 3 adjacent bytes form one line of the
|
||
sprite.
|
||
|
||
The start of the data block of each sprite can be chosen in steps of 64
|
||
bytes within the 16KB address space of the VIC. For this, the VIC reads a
|
||
sprite data pointer for each sprite in every raster line from the very last
|
||
8 bytes of the video matrix (p-access) that is then used as the upper 8 bits
|
||
of the address for sprite data accesses (s-accesses). The lower 6 bits come
|
||
from a sprite data counter (MC0-MC7, one for each sprite) that plays a
|
||
similar role for the sprites as VC does for the video matrix. As the
|
||
p-accesses are performed in every raster line you can change the appearance
|
||
of a sprite in the middle of its display by changing the sprite data
|
||
pointer.
|
||
|
||
When s-accesses are necessary for a sprite, they are performed in the three
|
||
half-cycles directly after the sprite's p-access. The VIC also uses the BA
|
||
and AEC signals (as for the Bad Lines) to access the bus in the second clock
|
||
phase. BA will also go low three cycles before the proper access in this
|
||
case. The s-accesses are done in every raster line in which the sprite is
|
||
visible (for the sprites 0-2, this always happens the line before, see the
|
||
timing diagrams in section 3.6.3.).
|
||
|
||
Like the text and bitmap graphics, the sprites also have a standard mode and
|
||
a multicolor mode. In standard mode, every bit directly corresponds to one
|
||
pixel on the screen. A "0" pixel is transparent and the underlying graphics
|
||
are visible below it, a "1" pixel is displayed in the respective sprite
|
||
color defined by registers $d027-$d02e. In multicolor mode, two adjacent
|
||
bits each form one pixel, thus reducing the resolution of the sprite to
|
||
12×21 pixels, with the pixels being twice as wide.
|
||
|
||
Moreover, the sprites can be doubled in their size on the screen in X and/or
|
||
Y direction (X/Y expansion). The sprite resolution doesn't change but each
|
||
sprite pixel simply becomes twice as wide or tall. So a pixel of an
|
||
x-expanded multicolor sprite is four times as wide as a pixel of an
|
||
unexpanded standard-mode sprite. Although both expansions look similar, they
|
||
are implemented completely differently in the VIC. The X expansion simply
|
||
instructs the sprite data sequencer to output pixels at half frequency. But
|
||
the Y expansion makes the sprite address generator read from the same
|
||
addresses two lines in succession so that every sprite line is output twice.
|
||
|
||
Each sprite has its own sprite data sequencer whose core is a 24-bit shift
|
||
register. Apart from that, there are two internal registers for every
|
||
sprite:
|
||
|
||
· "MC" (MOB Data Counter) is a 6-bit counter that can be loaded from
|
||
MCBASE.
|
||
· "MCBASE" (MOB Data Counter Base) is a 6-bit register that can be loaded
|
||
from MC or reset to zero.
|
||
|
||
Apart from these, there is one “advance line” flip-flop per sprite that
|
||
is used to control the Y expansion.
|
||
|
||
The display of a sprite is handled according to the following rules (the
|
||
cycle numbers are only valid for the 6569):
|
||
|
||
1. The advance line flip-flop is set as long as the corresponding MxYE bit
|
||
in register $d017 is cleared.
|
||
|
||
2. In the first phases of cycle 55 and 56, the VIC checks for every sprite
|
||
if the corresponding MxE bit in register $d015 is set and the Y
|
||
coordinate of the sprite (odd registers $d001-$d00f) matches the lower 8
|
||
bits of RASTER. If this is the case and the DMA for the sprite is still
|
||
off, the DMA is switched on, MCBASE is cleared, and the advance line
|
||
flip-flop is set.
|
||
|
||
3. If the MxYE bit of a sprite is set in the second phase of cycle 56 and
|
||
the DMA for that sprite is on, then the advance line flip-flop is
|
||
inverted.
|
||
|
||
4. In the first phase of cycle 58, the MC of every sprite is loaded from
|
||
its corresponding MCBASE (MCBASE->MC) and the VIC checks if the DMA for
|
||
the sprite is turned on and the Y coordinate of the sprite matches the
|
||
lower 8 bits of RASTER. If this is the case, the display of the sprite is
|
||
turned on. Otherwise, if the DMA for the sprite is turned off, then its
|
||
display is also turned off.
|
||
|
||
5. If the DMA for a sprite is turned on, three s-accesses are performed in
|
||
sequence in the corresponding cycles assigned to the sprite (see the
|
||
diagrams in section 3.6.3.). The p-accesses are always done, even if the
|
||
sprite is turned off. The read data of the first access is stored in the
|
||
upper 8 bits of the shift register, that of the second one in the middle
|
||
8 bits and that of the third one in the lower 8 bits. MC is incremented
|
||
by one after each s-access.
|
||
|
||
6. If the sprite display for a sprite is turned on, the shift register is
|
||
shifted left by one bit with every pixel as soon as the current X
|
||
coordinate of the raster beam has matched the X coordinate of the sprite
|
||
(even registers $d000-$d00e), and the bits that are shifted out are
|
||
displayed. If the MxXE bit belonging to the sprite in register $d01d is
|
||
set, the register is only shifted every second pixel and the sprite thus
|
||
appears twice as wide. If the sprite is in multicolor mode, two adjacent
|
||
bits each form one pixel.
|
||
|
||
7. In the first phase of cycle 16, the VIC checks for each sprite if its
|
||
advance line flip-flop is set. If so, MCBASE is loaded from its
|
||
corresponding MC (MC->MCBASE), thus advancing the sprite display to the
|
||
next line. After that, the VIC checks if MCBASE is equal to 63 and turns
|
||
off the DMA of the sprite if this is the case.
|
||
|
||
7a. As a special case, if the CPU has cleared one of the MxYE bits in cycle
|
||
15 and the advance line flip-flop of the corresponding sprite was not
|
||
set, then the flip-flop is set and in the next cycle (16) the VIC sets
|
||
MCBASE not to MC but to:
|
||
MCBASE = ((101010 & (MCBASE & MC)) | (010101 & (MCBASE | MC))
|
||
|
||
As the test in rule 2 is performed at the end of a raster line, the sprite Y
|
||
coordinates stored in the registers must be 1 less than the desired Y
|
||
position of the first sprite line, as the sprite display will not start
|
||
before the following line, after the first sprite data has been read (as
|
||
long as the sprite is not positioned to the right of sprite X coordinate
|
||
$164 (cycle 58, see rule 4)).
|
||
|
||
Sprites can be "reused" vertically: If you change the Y coordinate of a
|
||
sprite to a later raster line during or after its display has completed, so
|
||
that the comparisons mentioned in rules 1 and 2 will match again, the sprite
|
||
is displayed again at that Y coordinate (you may then of course also set a
|
||
new X coordinate and sprite data pointer). It is therefore possible to
|
||
display more than 8 sprites on the screen, which is usually referred to as
|
||
"sprite multiplexing" and is an official design feature of the VIC.
|
||
|
||
This is not possible in the horizontal direction. After 24 displayed pixels,
|
||
the shift register has run empty and even if you change the X coordinate
|
||
within a line so that the comparison in rule 6 will match again, no sprite
|
||
data is displayed any more. So you can only display up to 8 sprites within
|
||
one raster line at a time. Also note that on a 6569, sprites with an X
|
||
position in the range $1f8-$1ff become invisible because these values are
|
||
never reached by the X raster counter; to place a sprite one pixel to the
|
||
left of X position 0 it has to be at X position $1f7.
|
||
|
||
Here is an overview of the scheme of p- and s-accesses:
|
||
|
||
p-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|VM13|VM12|VM11|VM10| 1 | 1 | 1 | 1 | 1 | 1 | 1 |Sprite number |
|
||
+----+----+----+----+----+----+----+----+----+----+----+--------------+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| MP7| MP6| MP5| MP4| MP3| MP2| MP1| MP0|
|
||
+----+----+----+----+----+----+----+----+
|
||
|
||
s-access
|
||
|
||
Addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| MP7| MP6| MP5| MP4| MP3| MP2| MP1| MP0| MC5| MC4| MC3| MC2| MC1| MC0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
Data
|
||
|
||
+----+----+----+----+----+----+----+----+
|
||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+
|
||
| 8 pixels (1 bit/pixel) |
|
||
| | MxMC = 0
|
||
| "0": Transparent |
|
||
| "1": Sprite color ($d027-$d02e) |
|
||
+---------------------------------------+
|
||
| 4 pixels (2 bits/pixel) |
|
||
| |
|
||
| "00": Transparent | MxMC = 1
|
||
| "01": Sprite multicolor 0 ($d025) |
|
||
| "10": Sprite color ($d027-$d02e) |
|
||
| "11": Sprite multicolor 1 ($d026) |
|
||
+---------------------------------------+
|
||
|
||
3.8.2. Priority and collision detection
|
||
---------------------------------------
|
||
|
||
As soon as several graphics elements (sprites and text/bitmap graphics)
|
||
overlap on the screen, the VIC has to decide which element shall be
|
||
displayed in the foreground [7]. To do this, every element has an assigned
|
||
priority, and only the element with highest priority is displayed.
|
||
|
||
The sprites have a fixed hierarchy among themselves: Sprite 0 has the
|
||
highest and sprite 7 the lowest priority. If two sprites overlap, the sprite
|
||
with the higher number is displayed only where the other sprite has a
|
||
transparent pixel.
|
||
|
||
The priority of the sprites to the text/bitmap graphics can be controlled
|
||
within some limits. First of all, the text/bitmap graphics are divided into
|
||
foreground pixels and background pixels. Which bit combinations belong to
|
||
the foreground or background is decided by the MCM bit in register $d016,
|
||
independently of the state of the graphics data sequencer and of the BMM and
|
||
ECM bits in register $d011:
|
||
|
||
| MCM=0 | MCM=1
|
||
------------+-------+-----------
|
||
Bits/pixel | 1 | 2
|
||
Pixels/byte | 8 | 4
|
||
Background | "0" | "00", "01"
|
||
Foreground | "1" | "10", "11"
|
||
|
||
In multicolor mode (MCM=1), the bit combinations "00" and "01" belong to the
|
||
background and "10" and "11" to the foreground, whereas in standard mode
|
||
(MCM=0), "0" pixels belong to the background and "1" pixels to the
|
||
foreground. It should be noted that this is also valid for the graphics
|
||
generated in idle state.
|
||
|
||
Of course, graphics elements with lower priority than any overlaid sprites
|
||
are visible where all the sprites have transparent pixels.
|
||
|
||
With the MxDP bits from register $d01b, you can separately specify for each
|
||
sprite whether it shall be displayed in front of or behind the foreground
|
||
pixels (the table in [2] is wrong):
|
||
|
||
MxDP=0:
|
||
|
||
+-----------------------+
|
||
| Background graphics | low priority
|
||
+-----------------------+ |
|
||
| Foreground graphics |-+
|
||
+-----------------------+ |
|
||
| Sprite x |-+
|
||
+-----------------------+ |
|
||
| Screen border |-+
|
||
| | high priority
|
||
+-----------------------+
|
||
|
||
MxDP=1:
|
||
|
||
+-----------------------+
|
||
| Background graphics | low priority
|
||
+-----------------------+ |
|
||
| Sprite x |-+
|
||
+-----------------------+ |
|
||
| Foreground graphics |-+
|
||
+-----------------------+ |
|
||
| Screen border |-+
|
||
| | high priority
|
||
+-----------------------+
|
||
|
||
In the latter case, those foreground graphics pixels which overlap
|
||
non-transparent sprite pixels "inherit" the priority of the sprite. For
|
||
example, if sprite 0 is set to appear behind the foreground (M0DP=1) then
|
||
the foreground pixels which overlap the image of sprite always stay visible,
|
||
even if sprite 0 overlaps with lower-priority sprites which are configured
|
||
to appear in front of the foreground (MxDP=0).
|
||
|
||
This behavior is hard to represent consistently in a simple picture of
|
||
stacked graphics layers:
|
||
|
||
+-----------------------+
|
||
| Background graphics | low priority
|
||
+-----------------------+ |
|
||
| Foreground graphics |-+
|
||
| visible through |
|
||
| sprites 1 and 0 |
|
||
+-----------------------+ |
|
||
| Sprite 1 |-+
|
||
+-----------------------+ |
|
||
| Sprite 0 |-+
|
||
+-----------------------+ |
|
||
| Foreground graphics |-+
|
||
| in front of sprite 0 |
|
||
+-----------------------+ |
|
||
| Screen border |-+
|
||
| | high priority
|
||
+-----------------------+
|
||
|
||
One way to think about this is to imagine the foreground pixels which
|
||
overlay a sprite becoming "baked into" the sprite image itself and be
|
||
handled with the sprite's priority from then on.
|
||
|
||
If you choose one of the invalid video modes only the sprites will be
|
||
visible (fore- and background graphics will all become black, see sections
|
||
3.7.3.6.-3.7.3.8.), but by setting the sprites to appear behind the
|
||
foreground graphics, the foreground graphics will actually become visible as
|
||
black pixels overlaying the sprite image.
|
||
|
||
In addition to the priority management, the VIC has the ability to detect
|
||
collisions of sprites among themselves and of sprites and foreground pixels
|
||
of the text/bitmap graphics.
|
||
|
||
A collision of sprites among themselves is detected as soon as two or more
|
||
sprite data sequencers output a non-transparent pixel in the course of
|
||
display generation (this can also happen somewhere outside of the visible
|
||
screen area). In this case, the MxM bits of any affected sprites are set in
|
||
register $d01e and (if allowed, see section 3.12.), an interrupt is
|
||
generated. The bits remain set until the register is read by the processor
|
||
and are cleared automatically by the read access.
|
||
|
||
A collision of sprites and other graphics data is detected as soon as one
|
||
or more sprite data sequencers output a non-transparent pixel and the
|
||
graphics data sequencer outputs a foreground pixel in the course of display
|
||
generation. In this case, the MxD bits of the affected sprites are set in
|
||
register $d01f and (if allowed, see section 3.12.), an interrupt is
|
||
generated. As with the sprite-sprite collision, the bits remain set until
|
||
the register is read by the processor.
|
||
|
||
If the vertical border flip-flop is set (normally within the upper/lower
|
||
border, see next section), the output of the graphics data sequencer is
|
||
turned off and there are no collisions of sprites with graphics data.
|
||
|
||
3.9. The border unit
|
||
--------------------
|
||
|
||
The VIC uses two flip-flops to generate the border around the display
|
||
window: A main border flip-flop and a vertical border flip-flop.
|
||
|
||
The main border flip-flop controls the border display. If it is set, the VIC
|
||
displays the color stored in register $d020, otherwise it displays the color
|
||
that the priority multiplexer switches through from the graphics or sprite
|
||
data sequencer. So the border overlays the text/bitmap graphics as well as
|
||
the sprites. It has the highest display priority.
|
||
|
||
The vertical border flip-flop is for auxiliary control of the upper/lower
|
||
border. If it is set, the main border flip-flop cannot be reset. Apart from
|
||
that, the vertical border flip-flop controls the output of the graphics data
|
||
sequencer. The sequencer only outputs data if the flip-flop is not set,
|
||
otherwise it displays the background color. This was probably done to
|
||
prevent sprite-graphics collisions in the border area.
|
||
|
||
There are 2×2 comparators belonging to each of the two flip-flops. These
|
||
comparators compare the X/Y position of the raster beam with one of two
|
||
hardwired values, depending on the state of the CSEL and RSEL bits, to
|
||
control the flip-flops. The comparisons only match if the values are reached
|
||
precisely. There is no comparison with an interval.
|
||
|
||
The horizontal comparison values are:
|
||
|
||
| CSEL=0 | CSEL=1
|
||
------+------------+-----------
|
||
Left | 31 ($1f) | 24 ($18)
|
||
Right | 335 ($14f) | 344 ($158)
|
||
|
||
And the vertical ones are:
|
||
|
||
| RSEL=0 | RSEL=1
|
||
-------+-----------+----------
|
||
Top | 55 ($37) | 51 ($33)
|
||
Bottom | 247 ($f7) | 251 ($fb)
|
||
|
||
The flip-flops are switched according to the following rules:
|
||
|
||
1. When the X coordinate reaches the right comparison value, the main border
|
||
flip-flop is set.
|
||
|
||
2. When the Y coordinate reaches the bottom comparison value in cycle 63,
|
||
the vertical border flip-flop is set.
|
||
|
||
3. When the Y coordinate reaches the top comparison value in cycle 63 and
|
||
the DEN bit in register $d011 is set, the vertical border flip-flop is
|
||
reset.
|
||
|
||
4. When the X coordinate reaches the left comparison value and the Y
|
||
coordinate reaches the bottom one, the vertical border flip-flop is set.
|
||
|
||
5. When the X coordinate reaches the left comparison value and the Y
|
||
coordinate reaches the top one and the DEN bit in register $d011 is set,
|
||
the vertical border flip-flop is reset.
|
||
|
||
6. When the X coordinate reaches the left comparison value and the vertical
|
||
border flip-flop is not set, the main flip-flop is reset.
|
||
|
||
So the Y coordinate is checked once or twice within each raster line: In
|
||
cycle 63 and when the X coordinate reaches the left comparison value.
|
||
|
||
By appropriate switching of the CSEL/RSEL bits you can prevent the
|
||
comparison values from being reached and thus turn off the border partly or
|
||
completely (see 3.14.1.).
|
||
|
||
3.10. Display Enable
|
||
--------------------
|
||
|
||
The DEN bit (Display Enable, register $d011, bit 4) allows switching the
|
||
text/bitmap graphics on or off. It is normally set. The bit affects two
|
||
functions of the VIC: The Bad Lines and the vertical border unit.
|
||
|
||
- A Bad Line Condition can only occur if the DEN bit has been set for at
|
||
least one cycle somewhere in raster line $30 (see section 3.5.).
|
||
- If the DEN bit is cleared, the reset input of the vertical border
|
||
flip-flop is deactivated (see section 3.9.). Thus the upper/lower border
|
||
will never be turned off.
|
||
|
||
So clearing the DEN bit will normally prevent Bad Lines (and thus c- and
|
||
g-accesses) from ever occurring and make the whole screen display the border
|
||
color.
|
||
|
||
3.11. Lightpen
|
||
--------------
|
||
|
||
On a negative edge of the LP input, the current position of the raster beam
|
||
is latched in the registers LPX ($d013) and LPY ($d014). LPX contains the
|
||
upper 8 bits (of 9) of the X position and LPY the lower 8 bits (likewise of
|
||
9) of the Y position. So the horizontal resolution of the light pen is
|
||
limited to 2 pixels.
|
||
|
||
Only one negative edge on LP is recognized per frame. If multiple edges
|
||
occur on LP, all following ones are ignored. The trigger is not released
|
||
until the start of the next frame.
|
||
|
||
As the LP input of the VIC is connected to the keyboard matrix, like the
|
||
lines of the joystick ports, it can also be controlled by software. This is
|
||
done via bit 4 of port B of CIA A ($dc01/$dc03). This allows determining the
|
||
current X position of the raster beam by triggering an LP edge and reading
|
||
from LPX afterwards (the VIC has no register that would allow reading the X
|
||
position directly). This can, for example, be used for cycle-exact
|
||
synchronization of raster interrupt routines.
|
||
|
||
The values you get from the LPX register can be calculated from the sprite
|
||
coordinates of the timing diagrams in section 3.6.3. The reference point is
|
||
the end of the cycle in which the LP line is triggered. For example, if you
|
||
trigger LP in cycle 20, you get the value $1e in LPX, corresponding to the
|
||
sprite coordinate $03c (LPX contains the upper 8 bits of the 9 bit X
|
||
coordinate).
|
||
|
||
The VIC is also able to trigger an interrupt on a negative edge of the LP
|
||
pin (see next section), likewise only once per frame.
|
||
|
||
3.12. VIC interrupts
|
||
--------------------
|
||
|
||
The VIC has the possibility to generate interrupts for the processor when
|
||
certain events occur. For this purpose, the IRQ output of the VIC is
|
||
connected to the IRQ input of the 6510. The VIC interrupts are therefore
|
||
maskable with the I flag in the processor status register.
|
||
|
||
There are four interrupt sources in the VIC. Each source has a corresponding
|
||
bit in the interrupt latch (register $d019) and a bit in the interrupt
|
||
enable register ($d01a). When an interrupts occurs, the corresponding bit in
|
||
the latch is set. To clear it, the processor has to write a "1" there "by
|
||
hand". The VIC doesn't clear the latch on its own.
|
||
|
||
If at least one latch bit and the corresponding bit in the enable register
|
||
is set, the VIC holds the IRQ line low and thereby triggers an interrupt in
|
||
the processor. So the four interrupt sources can be independently enabled
|
||
and disabled using the enable bits. Since the VIC, as mentioned, doesn't
|
||
clear the interrupt latch by itself, the processor has to do this before it
|
||
resets the I flag or returns from the interrupt routine. Otherwise the
|
||
interrupt will be re-triggered immediately (the IRQ input of the 6510 is
|
||
state-sensitive).
|
||
|
||
The following table describes the four interrupt sources and their bits in
|
||
the latch and enable registers:
|
||
|
||
Bit|Name| Trigger condition
|
||
---+----+-----------------------------------------------------------------
|
||
0 | RST| Reaching a certain raster line. The line is specified by writing
|
||
| | to register $d012 and bit 7 of $d011, and internally stored by
|
||
| | the VIC for the raster compare. The test for reaching the
|
||
| | interrupt raster line is done in cycle 1 of every line (for line
|
||
| | 0, in cycle 2). It is possible to trigger an interrupt
|
||
| | immediately by writing to $d011/$d012, but the interrupt can
|
||
| | never occur more than once per raster line.
|
||
1 | MBC| Collision of at least one sprite with the text/bitmap graphics
|
||
| | (one sprite data sequencer outputs non-transparent pixel at the
|
||
| | same time at which the graphics data sequencer outputs a
|
||
| | foreground pixel)
|
||
2 | MMC| Collision of two or more sprites (two sprite data sequencers
|
||
| | output a non-transparent pixel at the same time)
|
||
3 | LP | Negative edge on the LP input (lightpen)
|
||
|
||
For the MBC and MMC interrupts, only the first collision will trigger an
|
||
interrupt (i.e. if the collision registers $d01e or $d01f contained the
|
||
value zero before the collision). To trigger further interrupts after a
|
||
collision, the respective register has to be cleared first by reading from
|
||
it.
|
||
|
||
The bit 7 in the latch $d019 reflects the inverted state of the IRQ output
|
||
of the VIC.
|
||
|
||
3.13. DRAM refresh
|
||
------------------
|
||
|
||
The VIC performs five read accesses in every raster line for refreshing the
|
||
dynamic RAM. An 8-bit refresh counter (REF) is used to generate 256 DRAM row
|
||
addresses. The counter is reset to $ff in raster line 0 and decremented by 1
|
||
after each refresh access. When the counter underflows, it wraps back to
|
||
$ff.
|
||
|
||
So the VIC will access addresses $3fff, $3ffe, $3ffd, $3ffc and $3ffb in
|
||
line 0, addresses $3ffa, $3ff9, $3ff8, $3ff7 and $3ff6 in line 1 etc.
|
||
|
||
Refresh addresses
|
||
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
| 1 | 1 | 1 | 1 | 1 | 1 |REF7|REF6|REF5|REF4|REF3|REF2|REF1|REF0|
|
||
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||
|
||
3.14. Effects and applications
|
||
------------------------------
|
||
|
||
The following sections will describe some graphical effects that can be
|
||
achieved by applying the rules and mechanisms of the VIC described in the
|
||
previous sections.
|
||
|
||
3.14.1. Hyperscreen
|
||
-------------------
|
||
|
||
As explained in section 3.9. the VIC generates the screen border by
|
||
comparing the beam coordinates with start and stop positions selected by the
|
||
CSEL/RSEL bits. This basically means that the border is not necessarily
|
||
displayed within a certain range of coordinates, but rather turned on and
|
||
off at certain coordinates. If you now make sure by appropriately switching
|
||
CSEL/RSEL that the coordinate comparison never matches, the border may for
|
||
example never turn on, allowing graphics in the border area to become
|
||
visible that would normally be covered. The technique is called
|
||
"hyperscreen" or "opening the border".
|
||
|
||
However, the graphics that can be displayed in the border area is mainly
|
||
limited to sprites, since the graphics data sequencer is in idle state in
|
||
this area as no Bad Lines can occur outside of Y coordinates $30-$f7 (see
|
||
section 3.5.). But you can still make use of the graphics generated in idle
|
||
state.
|
||
|
||
To turn off the upper/lower border, you proceed as follows:
|
||
|
||
1. Somewhere in the upper part of the screen, switch to 25-line-border by
|
||
setting the RSEL bit.
|
||
|
||
2. Now wait until RASTER has reached a value in the range of 248-250. The
|
||
vertical border flip-flop is still cleared as the comparison value for
|
||
RSEL=1 is raster line 251.
|
||
|
||
3. Then clear the RSEL bit. The comparator is switched and now sets the
|
||
vertical flip-flop at line 247. But this line has already passed and thus
|
||
the VIC "forgets" to turn on the vertical border.
|
||
|
||
4. After raster line 251, set the RSEL bit again and repeat from step 2.
|
||
|
||
If you open the upper/lower border with this method, the left/right border
|
||
still remains active in the "opened up" area. If you switch from RSEL=0 to
|
||
RSEL=1 in the raster line range 52-54, the border never turns off and covers
|
||
the whole screen (similar to when the DEN bit is cleared, but Bad Lines
|
||
still occur). This is interesting but not very useful.
|
||
|
||
The left/right border can be turned off with the CSEL bit in a similar way.
|
||
However, the timing is much more critical here. Whereas for the vertical
|
||
border, you have 4 raster lines for the switch, for the horizontal border
|
||
the change from CSEL=1 to CSEL=0 has to be exactly in cycle 56. Likewise,
|
||
the horizontal border can be prevented from turning off by switching from
|
||
CSEL=0 to CSEL=1 in cycle 17.
|
||
|
||
If you want to open the left/right border in the upper/lower border area,
|
||
you must either start before the vertical border flip-flop is set (i.e.
|
||
outside of the upper/lower border), or also open the upper/lower border.
|
||
This is because the main border flip-flop can only be reset if the vertical
|
||
flip-flop is not set. If you compare both methods, you can verify that the
|
||
vertical flip-flop also controls the graphics data sequencer output: With
|
||
the first method, only the background color is visible in the opened up
|
||
upper/lower border area, whereas the second method displays the idle state
|
||
graphics there.
|
||
|
||
3.14.2. FLD
|
||
-----------
|
||
|
||
When building the graphics out of text lines, the VIC is directed
|
||
exclusively by the occurrence of Bad Lines: A Bad Line gives the "start
|
||
signal" for the display of one text line. By appropriately changing YSCROLL
|
||
(in register $d011) you can suppress and arbitrarily delay the Bad Line
|
||
Condition (see 3.5.). In this way you can exactly control in which raster
|
||
lines Bad Lines should occur and thus from which raster lines the VIC should
|
||
start to display one text line. The distance between two text lines can be
|
||
arbitrarily increased if you hold back the next Bad Line long enough. This
|
||
effect is called "Flexible Line Distance" (FLD).
|
||
|
||
For example, if you only allow three Bad Lines on the screen at raster lines
|
||
$50, $78 and $a0, the VIC will also only display three text lines at these
|
||
positions. The sequencer is in idle state in the lines between.
|
||
|
||
If you only delay the occurrence of the first Bad Line, you can scroll down
|
||
the entire graphics display by large distances without moving a single byte
|
||
in display memory.
|
||
|
||
3.14.3. FLI
|
||
-----------
|
||
|
||
Instead of delaying the occurrence of Bad Lines as for the FLD effect, you
|
||
can also artificially create an additional Bad Line before the VIC has
|
||
completed the current text line. This is especially interesting for the
|
||
bitmap modes, as these use the data from the video matrix (which is read in
|
||
the Bad Lines) for color information, so normally only 8×8 pixel blocks each
|
||
can be colored individually in bitmap modes. But if you make every raster
|
||
line a Bad Line by appropriately modifying YSCROLL, then the VIC will read
|
||
from the video matrix in every line and so it will also read new color
|
||
information for each line.
|
||
|
||
This way, each of the 4×8 pixels of a block in multicolor mode can have a
|
||
different color. This software-generated new graphics mode is called
|
||
"Flexible Line Interpretation" (FLI) and is probably the most outstanding
|
||
example of "unconventional" VIC programming.
|
||
|
||
There is however one problem: If you create a new Bad Line before the
|
||
current text line has been finished, VCBASE is not incremented (see section
|
||
3.7.2.). The VIC therefore reads from the same addresses of the video matrix
|
||
as in the previous line. Since you cannot change the video matrix fast
|
||
enough from the processor, you have to switch the base address of the video
|
||
matrix with the bits VM10-VM13 of register $d018 if you want different
|
||
colors for each pixel line. Unfortunately the Color RAM cannot be switched,
|
||
so the color selection of the pixels is not entirely free.
|
||
|
||
Also, the access to $d011 to create the Bad Line must not happen until cycle
|
||
14 of each raster line, or otherwise the RC would be cleared in every line
|
||
and the bitmap display would not be as desired. But this also implies that
|
||
the first three c-accesses of the VIC in each line do not read valid data,
|
||
because the first c-access in cycle 15 requires that BA should have gone low
|
||
in cycle 12 so that AEC can stay low in cycle 15 (AEC doesn't stay low until
|
||
three cycles after the negative edge of BA; there is no way around that).
|
||
Since the Bad Line was generated in cycle 14, while BA is now low in cycle
|
||
15 on the first c-access, AEC is still high, however, and so the internal
|
||
data bus gates D0-D7 of the VIC are closed and the chip reads the value $ff
|
||
instead of the video matrix data (the data bus gates D8-D11 are indeed open,
|
||
but this will be explained in section 3.14.6. in more detail). This stray
|
||
data is visible as 24-pixel wide stripes on the left side of the screen.
|
||
|
||
In practice, you place eight video matrices in memory that are used in the
|
||
following way: In the first raster line the first line of the first matrix,
|
||
in the second line the first line of the second matrix, etc., in the
|
||
eighth line the first line of the eighth matrix, in the ninth line the
|
||
second line of the first matrix, etc. With these eight matrices you can
|
||
cover a complete bitmap in line-wise fashion.
|
||
|
||
There are several flavors of the FLI mode, such as AFLI (Advanced FLI) which
|
||
uses the standard bitmap mode and simulates color blends with similarly
|
||
colored adjacent pixels, and IFLI (Interlaced FLI) that alternates between
|
||
two frames in a simulated interlace mode.
|
||
|
||
3.14.4. Linecrunch
|
||
------------------
|
||
|
||
By manipulating YSCROLL, you have even more possibilities for controlling
|
||
the Bad Lines. You may also abort a Bad Line before its correct completion
|
||
by negating the Bad Line Condition within an already begun Bad Line before
|
||
cycle 14. This his several consequences:
|
||
|
||
· The graphics data is in display state, so graphics are displayed.
|
||
· The RC is not reset. If you abort the very first line of a frame this
|
||
way, the RC is still at 7 from the last line of the previous frame.
|
||
· In cycle 58 of the line the RC is still 7, so the sequencer goes to idle
|
||
state and VCBASE is loaded from VC. But since the sequencer has been in
|
||
display state within the line, VC has been incremented after every
|
||
g-access, so VCBASE has now been effectively increased by 40. The RC
|
||
doesn't overflow, it stays at 7.
|
||
|
||
With this procedure you have reduced the display of a text line to its last
|
||
raster line, because as VCBASE has been incremented by 40, the VIC continues
|
||
with the next line. This effect if therefore called "Linecrunch": You can
|
||
"crunch" single text lines with it.
|
||
|
||
If you now do this in every raster line, the RC will always stay at 7 and
|
||
there will be no c-accesses, but VCBASE is incremented by 40 in every line.
|
||
This eventually makes VCBASE cross the 1000 byte limit of the video matrix
|
||
and the VIC will display the last, normally invisible, 24 bytes of the
|
||
matrix (where also the sprite data pointers are stored). VCBASE wraps around
|
||
to zero when reaching 1024.
|
||
|
||
By crunching whole text lines to one raster line each you have the
|
||
possibility to quickly scroll the screen contents upwards by large distances
|
||
without moving bytes in the graphics memory, in a similar way as you can
|
||
scroll it downwards with FLD. The only disturbing side effect is that the
|
||
crunched lines will pile up near the upper screen border, looking awkward.
|
||
Here it is possible to use one of the invalid graphics modes to blank out
|
||
these lines.
|
||
|
||
3.14.5. Doubled text lines
|
||
--------------------------
|
||
|
||
The display of a text line is normally finished after 8 raster lines,
|
||
because then RC=7 and in cycle 58 of the last line the sequencer goes to
|
||
idle state (see section 3.7.2.). But if you now assert a Bad Line Condition
|
||
between cycles 54-57 of the last line, the sequencer stays in display state
|
||
and the RC is incremented again (and thus overflows to zero). The VIC will
|
||
then in the next line start again with the display of the previous text
|
||
line. But as no new video matrix data has been read, the previous text line
|
||
is simply displayed twice.
|
||
|
||
3.14.6. DMA delay / VSP
|
||
-----------------------
|
||
|
||
The most sophisticated Bad Line manipulation is to create a Bad Line
|
||
Condition in cycles 15-53 of a raster line of display window, in which the
|
||
graphics data sequencer is in idle state, for example by modifying register
|
||
$d011 so that YSCROLL is now equal to the lower three bits of RASTER.
|
||
|
||
The VIC will then set BA low immediately in the next cycle, switch to
|
||
display state and start reading from the video matrix. The processor is now
|
||
stopped because BA is low and it wants to read the next opcode. However, AEC
|
||
still follows ϕ0 for three cycles before also staying at the low state. This
|
||
behavior (AEC not until three cycles after BA) is hardwired in the VIC and
|
||
cannot be avoided.
|
||
|
||
Nevertheless, the VIC accesses the video matrix, or at least it tries,
|
||
because as long as AEC is still high in the second clock phase, the address
|
||
and data bus lines D0-D7 of the VIC are in tri-state in the first three
|
||
cycles, so the VIC reads the value $ff from D0-D7 instead of the data from
|
||
the video matrix. The data lines D8-D13 of the VIC, however, don't have
|
||
tri-state drivers and are always set to input. But the VIC doesn't get valid
|
||
Color RAM data from there either, because with AEC being high, the 6510 is
|
||
still considered the bus master and unless it by chance wants to read the
|
||
next opcode from the Color RAM, the chip select input of the Color RAM is
|
||
not active. Instead, a 4 bit analog (!) switch, U16, connects the data bits
|
||
D0-D3 of the processor with the Color RAM data bits D8-D13. This connection
|
||
is always in place when AEC is high and allows the processor to access the
|
||
Color RAM if desired. To make a long story short: In the first three cycles
|
||
after BA went low the VIC reads $ff for the character pointers, and for the
|
||
color information the lower 4 bits of the opcode after the access to $d011.
|
||
Only then can it read regular video matrix data.
|
||
|
||
This data is stored just as usual at the start of the internal video
|
||
matrix/color line, and VC gets incremented after each following g-access
|
||
(with the generation of the Bad Line, the sequencer has also been put into
|
||
display state). The c- and g-accesses are continued until cycle 54. But
|
||
since the accesses started in the middle of a line, less than 40 of them
|
||
took place so VC is no longer a multiple of 40 at the end of the line.
|
||
Because of the way VC works (see section 3.7.2.), this "misalignment"
|
||
continues for all following lines. So the entire screen appears scrolled to
|
||
the right by as many characters as the number of cycles the $d011 access
|
||
took place after cycle 14. As the c-accesses within this line started later
|
||
than in a normal Bad Line, this procedure is called "DMA Delay" (or VSP for
|
||
"Virtual Screen Position").
|
||
|
||
With this method it is possible to scroll the complete screen sideways by
|
||
large distances (which also works with bitmap graphics in the same way
|
||
because the VC is also used for accessing the bitmap data) without having to
|
||
move the graphics memory with the processor. If you now combine DMA Delay
|
||
with FLD and Linecrunch, you can scroll entire graphics screens by almost
|
||
arbitrarily large distances in any direction, using very little computing
|
||
time.
|
||
|
||
Experimenting with DMA Delay (and with Bad Line effects in general) is also
|
||
the best method for discovering the internal functions of the VIC,
|
||
especially of RC and VC, and for determining in which cycles certain things
|
||
happen inside the VIC.
|
||
|
||
It should also be mentioned that DMA Delay can not only be achieved by
|
||
manipulating YSCROLL but also with the DEN bit of register $d011. To do
|
||
this, you have to set YSCROLL to zero so that raster line $30 becomes a bad
|
||
line and switch DEN from "0" to "1" in the middle of that line. This is
|
||
because Bad Lines can only occur if the DEN bit has been set for at least
|
||
one cycle in line $30, and if YSCROLL is zero a Bad Line Condition will
|
||
occur in line $30 as soon as DEN is set.
|
||
|
||
3.14.7 Sprite stretching / Sprite crunch
|
||
----------------------------------------
|
||
|
||
As the sprite circuitry is simpler than that for the text graphics, there
|
||
are not as many special effects possible with sprites, but among them is a
|
||
very interesting effect that takes advantage of the way the sprite Y
|
||
expansion works: By modifying the MxYE bits in register $d017 it is not only
|
||
possible to decide for each individual sprite line if it should be doubled,
|
||
but you can also repeat a single line three or more times and therefore
|
||
expand a sprite vertically by an arbitrary scaling factor.
|
||
|
||
This effect can be explained as follows (see section 3.8.1.):
|
||
|
||
Let's say that we are in cycle 55 of a raster line in which sprite 0 is
|
||
turned on, and whose Y coordinate matches the Y coordinate of the sprite, so
|
||
we are in the line before the sprite will be displayed. Suppose that the
|
||
M0YE bit is set. The VIC will then turn on the DMA for sprite 0, clear
|
||
MCBASE, and set the advance line flip-flop, which is then inverted in the
|
||
next cycle because of the set M0YE bit. BA goes to low state to allow the
|
||
VIC to access the sprite data in the second clock phases of cycles 58 and
|
||
59. In the first phase of cycle 58, MC is loaded from MCBASE (and so cleared
|
||
to zero as well), and the p-access for the sprite is performed. The VIC then
|
||
carries out the three s-accesses and increments MC after each access so it
|
||
now has the value 3.
|
||
|
||
Now you wait for cycle 16 of the following line. As the advance line
|
||
flip-flop is not set, MCBASE will still stay at zero. Now you clear the M0YE
|
||
bit, and thereby set the flip-flop, but then immediately set M0YE to "1"
|
||
again. Because M0YE remains set, the flip-flop will be inverted again in
|
||
cycle 56, and is therefore reset (if M0YE hadn't been cleared, the flip-flop
|
||
would now be set). But this is exactly the same state in which the VIC
|
||
already was in cycle 56 of the previous line. So the VIC "thinks" that it is
|
||
still in the first raster line of an expanded sprite and, since MC is still
|
||
zero, it will proceed to read the first sprite line twice more from memory,
|
||
three times in total: The first sprite line has been tripled.
|
||
|
||
Another interesting effect, known as "sprite crunch", can be achieved by
|
||
proceeding exactly as outlined above, but not clearing the M0YE bit after
|
||
cycle 16 but in the second phase of cycle 15. MCBASE will then be set to 1,
|
||
and the next sprite line is read from memory with MC=1..3, which is one byte
|
||
higher than normal. This misalignment continues in the entire display of the
|
||
sprite. The condition MC=63 for turning off the sprite DMA in cycle 16 is
|
||
therefore also not met, and the sprite is effectively displayed twice in a
|
||
row. Not until the end of the second display does the VIC finally turn off
|
||
the DMA when MC reaches 63.
|
||
|
||
|
||
4. The addresses 0 and 1 and the $de00 area
|
||
-------------------------------------------
|
||
|
||
The address range $de00-$dfff of the 6510 (see 2.4.1.) is reserved for
|
||
external expansions of the C64 and normally not connected to any other
|
||
devices (RAM, I/O). A read access will fetch data that looks random at first
|
||
sight. The same is true for the upper nybbles of the addresses $d800-$dbff
|
||
(the Color RAM).
|
||
|
||
But on some C64 models, this data turns out to be not "random" at all but
|
||
rather identical to the data that the VIC has read from memory in the first
|
||
phase of the clock cycle. This effect is however not reproducible on all
|
||
machines and not always reliable.
|
||
|
||
Apart from the fact that this opens up the possibility of measuring the VIC
|
||
timing completely in software (the timing diagrams in [4] on which the
|
||
diagrams in this article are based have, for example, been created using
|
||
this method), you can also make the 6510 execute programs in the $de00-area
|
||
or in the Color RAM if the VIC displays graphics in such a way that the 6510
|
||
always gets valid opcodes from the graphics data read by the VIC.
|
||
|
||
With a similar effect you can also write to RAM addresses 0 and 1 from the
|
||
processor. These are normally not accessible as the internal data direction
|
||
register and data register of the 6510 I/O port are mapped to these
|
||
addresses, and the data bus drivers of the processor stay in tri-state on a
|
||
write access. But the R/W line is still set to low state, and so the byte
|
||
read by the VIC in the first clock phase will be written to RAM. If you want
|
||
to write a certain value to addresses 0 or 1 you only have to write an
|
||
arbitrary value to these addresses, taking care that the VIC has read the
|
||
value you want from RAM in the clock phase before.
|
||
|
||
The addresses 0 and 1 can of course also be read by the processor, either
|
||
via the $de00-area of with the aid of sprite collisions. For this, you make
|
||
the VIC display a bitmap starting at address 0 and move a sprite consisting
|
||
only of one pixel over the bits of the first two bytes of the bitmap.
|
||
Depending on whether the VIC detects a collision or not, you can find out
|
||
the state of the individual bits and put them together to one byte.
|
||
|
||
|
||
5. Revision history
|
||
-------------------
|
||
|
||
1996-08-28
|
||
- Original version
|
||
|
||
2000-02-10
|
||
- Corrected typos in sections 3.4, 3.6.3, and 3.8
|
||
- Minor editorial changes
|
||
|
||
2024-09-16
|
||
- Section 2.2: Added description of the ϕ0 pin
|
||
- Section 2.3: Added descriptions of the S/LUM, COLOR, and ϕCOLOR pins
|
||
- Section 3.3: Extended information about the VIC color palette
|
||
- Section 3.7.2: Corrected the explanation of the VMLI
|
||
- Sections 3.8.1 and 3.14.7: Corrected the explanation of sprite Y
|
||
expansion
|
||
- Section 3.8.2: More detailed description of the interaction between
|
||
sprite-sprite and sprite-foreground priorities
|
||
- Complete editorial revision
|
||
|
||
2024-09-29
|
||
- Section 3.12: Clarify raster interrupt behavior
|
||
|
||
|
||
Appendix A: Bibliography
|
||
------------------------
|
||
|
||
[1] Commodore Business Machines, "C64 Programmers Reference Guide",
|
||
Appendix L: "6510 microprocessor data sheet", 1984
|
||
|
||
[2] ditto, Appendix N: "6566/6567 Video Interface Controller (VIC-II) Chip
|
||
Specifications"
|
||
|
||
[3] ditto, Chapter 5, Section "Memory management on the Commodore 64"
|
||
|
||
[4] Marko Mäkelä, "The memory accesses of the MOS 6569 VIC-II and MOS 8566
|
||
VIC-IIe Video Interface Controller" (AKA: Pal timing), 1994-07-15
|
||
|
||
[5] John West, Marko Mäkelä, "Documentation for the NMOS 65xx/85xx
|
||
Instruction Set" (AKA: 64doc), 1994-06-03
|
||
|
||
[6] Albert J. Charpentier et al., "Digital sine-cosine generator",
|
||
United States Patent 4,551,682, Nov. 5, 1985
|
||
|
||
[7] James W. Redfield, Albert J. Charpentier, "Display logic circuit for
|
||
multiple object priority", United States Patent 4,561,659, Dec. 31, 1985
|
||
|
||
[8] Philip Timmermann, "Calculating the color palette of the VIC II"
|
||
https://www.pepto.de/projects/colorvic/ (accessed 2024-09-06)
|
||
|
||
|
||
Appendix B: Acknowledgments
|
||
---------------------------
|
||
|
||
I want to thank
|
||
|
||
- Marko Mäkelä, Andreas Boose, Pasi Ojala and Wolfgang Lorenz for the
|
||
amount of work they put into the examination of the VIC
|
||
- Kaspar Jensen for proof-reading the English version of this document and
|
||
for his suggestions
|
||
- Adam Vardy for pointing out that my description of idle state graphics
|
||
display was wrong
|
||
- Thilo Girmann for explaining the actual implementation of the VMLI on
|
||
the VIC
|
||
- Daniel Kahlin, Hannu Nuotio, Antti Lankila and Andreas Matthies for
|
||
figuring out how sprite Y expansion really works
|