Difference between revisions of "Sega Mega Drive/VDP general usage"
From Sega Retro
(Created page with "The '''VDP''' (Video Display Processor) is the main graphics processor in the Sega Mega Drive. It is capable of displaying two graphics planes - a foreground (plane A) and...") |
Ccawley2011 (talk | contribs) |
||
(8 intermediate revisions by one other user not shown) | |||
Line 5: | Line 5: | ||
==Ports== | ==Ports== | ||
Features of the VDP such as VRAM are not directly accessible by the 68k. Instead, all instructions and data must be sent through the control and data ports. | Features of the VDP such as VRAM are not directly accessible by the 68k. Instead, all instructions and data must be sent through the control and data ports. | ||
− | {| | + | {|class="prettytable" |
! 68k Address !! Length !! Description | ! 68k Address !! Length !! Description | ||
|- | |- | ||
− | | $C00000 || B/W/L || Data port | + | | $C00000 || B/W/L || [[#Data port|Data port]] |
|- | |- | ||
| $C00002 || B/W || Data port (mirror) | | $C00002 || B/W || Data port (mirror) | ||
|- | |- | ||
− | | $C00004 || B/W/L || Control port | + | | $C00004 || B/W/L || [[#Control port|Control port]] |
|- | |- | ||
| $C00006 || B/W || Control port (mirror) | | $C00006 || B/W || Control port (mirror) | ||
|- | |- | ||
− | | $C00008 || B/W || H/V counter (read-only) | + | | $C00008 || B/W || [[#H/V counter|H/V counter]] (read-only) |
|- | |- | ||
| $C0000A || B/W || H/V counter (read-only, mirror) | | $C0000A || B/W || H/V counter (read-only, mirror) | ||
Line 32: | Line 32: | ||
| $C00017 || B || SN76489 PSG (write-only, mirror) | | $C00017 || B || SN76489 PSG (write-only, mirror) | ||
|- | |- | ||
− | | $C0001C || W || Debug register | + | | $C0001C || W || [[#Debug register|Debug register]] |
|- | |- | ||
| $C0001E || W || Debug register (mirror) | | $C0001E || W || Debug register (mirror) | ||
Line 41: | Line 41: | ||
Reading the control port always returns the [[Sega Mega Drive/VDP registers#Status Register|status register]], which contains information about what the VDP is currently doing. | Reading the control port always returns the [[Sega Mega Drive/VDP registers#Status Register|status register]], which contains information about what the VDP is currently doing. | ||
− | <tt>move.w ($c00004).l,d0</tt> | + | : <tt>move.w ($c00004).l,d0</tt> |
===Writing=== | ===Writing=== | ||
− | Writing to the control port | + | ====Registers==== |
+ | Writing to the control port can modify one of 24 write-only [[Sega Mega Drive/VDP registers|registers]], which are used to change various settings, or to set up a DMA transfer. | ||
{{bitfield|1|0|0|RS4-RS0;5}}{{bitfield|D7-D0;8}} | {{bitfield|1|0|0|RS4-RS0;5}}{{bitfield|D7-D0;8}} | ||
Line 52: | Line 53: | ||
To modify a register, write a word (1 byte for the register number, 1 byte for the modification) to the control port: | To modify a register, write a word (1 byte for the register number, 1 byte for the modification) to the control port: | ||
− | <tt>move.w #$8004,($c00004).l ; set register 0 to $04</tt> | + | : <tt>move.w #$8004,($c00004).l ; set register 0 to $04</tt> |
Because the control port is mirrored at $c00006, it is possible to send two words at the same time: | Because the control port is mirrored at $c00006, it is possible to send two words at the same time: | ||
− | <tt>move.l #$80048134,($C00004).l ; set register 0 to $04 and register 1 to $34</tt> | + | : <tt>move.l #$80048134,($C00004).l ; set register 0 to $04 and register 1 to $34</tt> |
+ | |||
+ | ====Addresses==== | ||
+ | The control port can also be used to point to an address in VRAM, CRAM or VSRAM, so that the 68k can send data to that address via the data port. This is done by writing a longword in the following format: | ||
+ | |||
+ | {{bitfield|CD1|CD0|A13-A8;6}}{{bitfield|A7-A0;8}}{{bitfield|0|0|0|0|0|0|0|0}}{{bitfield|CD5|CD4|CD3|CD2|0|0|A15|A14}} | ||
+ | * '''A15-A0:''' VRAM/CRAM/VSRAM address. | ||
+ | * '''CD0:''' 1 = write; 0 = read. | ||
+ | * '''CD3-CD1:''' 000 = VRAM; 100 = CRAM (read); 001 = CRAM (write); 010 = VSRAM; 110 = VRAM (byte read) | ||
+ | * '''CD4:''' 1 = VRAM to VRAM copy. | ||
+ | * '''CD5:''' 1 = [[Sega Mega Drive/DMA|DMA]]. Used to automate data transfer without the need for the data port. | ||
+ | |||
+ | {|class="prettytable" | ||
+ | ! Memory space || Type || CD3-CD0 || Code | ||
+ | |- | ||
+ | |rowspan="2"| VRAM | ||
+ | | read | ||
+ | | 0000 | ||
+ | | <tt>move.l #$00000000+(($xxxx&$3FFF)<<16)+(($xxxx&$C000)>>14),($C00004).l</tt> | ||
+ | |- | ||
+ | | write | ||
+ | | 0001 | ||
+ | | <tt>move.l #$40000000+(($xxxx&$3FFF)<<16)+(($xxxx&$C000)>>14),($C00004).l</tt> | ||
+ | |- | ||
+ | |rowspan="2"| CRAM | ||
+ | | read | ||
+ | | 1000 | ||
+ | | <tt>move.l #$00000020+($xx<<16),($C00004).l</tt> | ||
+ | |- | ||
+ | | write | ||
+ | | 0011 | ||
+ | | <tt>move.l #$C0000000+($xx<<16),($C00004).l</tt> | ||
+ | |- | ||
+ | |rowspan="2"| VSRAM | ||
+ | | read | ||
+ | | 0100 | ||
+ | | <tt>move.l #$00000010+($xx<<16),($C00004).l</tt> | ||
+ | |- | ||
+ | | write | ||
+ | | 0101 | ||
+ | | <tt>move.l #$40000010+($xx<<16),($C00004).l</tt> | ||
+ | |- | ||
+ | |} | ||
==Data port== | ==Data port== | ||
+ | After an address has been set, data can be read or written at that location through the data port. If the [[Sega Mega Drive/VDP registers#0F|auto-increment register]] has been set, the address will increase by that amount after every read/write. Attempts to read during a write operation or vice-versa will be ignored. | ||
+ | |||
+ | As an example, the following code swaps first four colours of the first palette line (CRAM addresses 0 to 7) with the first four colours of the last palette line (CRAM addresses $60 to $67): | ||
+ | |||
+ | <pre> | ||
+ | lea ($C00004).l,a5 ; VDP control port | ||
+ | lea ($C00000).l,a6 ; VDP data port | ||
+ | move.w #$8F02,(a5) ; set auto-increment to 2 (see registers page for explanation) | ||
+ | |||
+ | move.l #$00000020,(a5) ; CRAM read at address $0 | ||
+ | move.l (a6),d0 ; get first two colours of first palette line | ||
+ | move.l (a6),d1 ; get next two colours of first palette line | ||
+ | move.l #$00600020,(a5) ; CRAM read at address $60 | ||
+ | move.l (a6),d2 ; get first two colours of last palette line | ||
+ | move.l (a6),d3 ; get next two colours of last palette line | ||
+ | |||
+ | move.l #$C0000000,(a5) ; CRAM write at address $0 | ||
+ | move.l d2,(a6) ; set first two colours of first palette line | ||
+ | move.l d3,(a6) ; set next two colours of first palette line | ||
+ | move.l #$C0600000,(a5) ; CRAM write at address $60 | ||
+ | move.l d0,(a6) ; set first two colours of last palette line | ||
+ | move.l d1,(a6) ; set next two colours of last palette line | ||
+ | </pre> | ||
+ | |||
+ | ==H/V counter== | ||
+ | The H/V counter contains the current position of the electron beam on the screen. It consists of two bytes: | ||
+ | |||
+ | {{bitfield|V7-V0;8}}{{bitfield|H8-H1;8}} | ||
+ | * '''V7-V0:''' Vertical position. | ||
+ | * '''H8-H1:''' Horizontal position. Lowest bit is omitted, so the value appears to be halved. | ||
+ | |||
+ | In interlace double resolution mode, the screen has twice as many scanlines and so the H/V counter is formatted differently: | ||
+ | |||
+ | {{bitfield|V7-V1;7|V8}}{{bitfield|H8-H1;8}} | ||
+ | * '''V8-V1:''' Vertical position. Lowest bit is omitted, so the value appears to be halved. | ||
+ | * '''H8-H1:''' Horizontal position. Lowest bit is omitted, so the value appears to be halved. | ||
+ | |||
+ | ==Debug register== | ||
+ | The debug register has various effects on VDP operation. Its features are undocumented and not known to be used by any games. | ||
+ | |||
+ | {{bitfield|?|LSB;3|CH;2|PV|L1}}{{bitfield|L0|D|?;6}} | ||
+ | * '''LSB:''' Locks the sprite buffer, resulting in some or all sprites becoming invisible. | ||
+ | * '''PV:''' 1 = set PSG volume to that of channel '''CH'''. | ||
+ | * '''CH:''' 00 = square 1; 01 = square 2; 10 = square 3; 11 = noise. | ||
+ | * '''L0-L1:''' Force layer visible: 00 = off; 01 = sprites; 10 = plane A; 11 = plane B. (Overrides bit '''D'''). | ||
+ | * '''D:''' 1 = disable display. Overrides [[Sega Mega Drive/VDP registers#01|VDP register 01]]. | ||
− | [[Category: | + | [[Category:Mega Drive technical information|VDP general usage]] |
− |
Latest revision as of 07:57, 3 October 2020
The VDP (Video Display Processor) is the main graphics processor in the Sega Mega Drive. It is capable of displaying two graphics planes - a foreground (plane A) and background (plane B) - which can be moved independently, as well as a static window plane, and up to 80 sprites (no more than 20 per scanline) on screen.
It contains 64kB of VRAM, used to store graphics data, nametable data for the three planes, horizontal scroll data for the foreground and background planes, and the sprite table. It also has 128 bytes of CRAM, used to store 64 colours (4 palettes of 16 colours). In practice, this equates to 61 usable colours since the first colour in each palette is transparent, and one of those is used as the "background" colour. Finally, VSRAM stores the vertical scroll data.
Contents
Ports
Features of the VDP such as VRAM are not directly accessible by the 68k. Instead, all instructions and data must be sent through the control and data ports.
68k Address | Length | Description |
---|---|---|
$C00000 | B/W/L | Data port |
$C00002 | B/W | Data port (mirror) |
$C00004 | B/W/L | Control port |
$C00006 | B/W | Control port (mirror) |
$C00008 | B/W | H/V counter (read-only) |
$C0000A | B/W | H/V counter (read-only, mirror) |
$C0000C | B/W | H/V counter (read-only, mirror) |
$C0000E | B/W | H/V counter (read-only, mirror) |
$C00011 | B | SN76489 PSG (write-only) |
$C00013 | B | SN76489 PSG (write-only, mirror) |
$C00015 | B | SN76489 PSG (write-only, mirror) |
$C00017 | B | SN76489 PSG (write-only, mirror) |
$C0001C | W | Debug register |
$C0001E | W | Debug register (mirror) |
Control port
Reading
Reading the control port always returns the status register, which contains information about what the VDP is currently doing.
- move.w ($c00004).l,d0
Writing
Registers
Writing to the control port can modify one of 24 write-only registers, which are used to change various settings, or to set up a DMA transfer.
- RS4-RS0: Register number.
- D7-D0: Data to write to register.
To modify a register, write a word (1 byte for the register number, 1 byte for the modification) to the control port:
- move.w #$8004,($c00004).l ; set register 0 to $04
Because the control port is mirrored at $c00006, it is possible to send two words at the same time:
- move.l #$80048134,($C00004).l ; set register 0 to $04 and register 1 to $34
Addresses
The control port can also be used to point to an address in VRAM, CRAM or VSRAM, so that the 68k can send data to that address via the data port. This is done by writing a longword in the following format:
- A15-A0: VRAM/CRAM/VSRAM address.
- CD0: 1 = write; 0 = read.
- CD3-CD1: 000 = VRAM; 100 = CRAM (read); 001 = CRAM (write); 010 = VSRAM; 110 = VRAM (byte read)
- CD4: 1 = VRAM to VRAM copy.
- CD5: 1 = DMA. Used to automate data transfer without the need for the data port.
Memory space | Type | CD3-CD0 | Code |
---|---|---|---|
VRAM | read | 0000 | move.l #$00000000+(($xxxx&$3FFF)<<16)+(($xxxx&$C000)>>14),($C00004).l |
write | 0001 | move.l #$40000000+(($xxxx&$3FFF)<<16)+(($xxxx&$C000)>>14),($C00004).l | |
CRAM | read | 1000 | move.l #$00000020+($xx<<16),($C00004).l |
write | 0011 | move.l #$C0000000+($xx<<16),($C00004).l | |
VSRAM | read | 0100 | move.l #$00000010+($xx<<16),($C00004).l |
write | 0101 | move.l #$40000010+($xx<<16),($C00004).l |
Data port
After an address has been set, data can be read or written at that location through the data port. If the auto-increment register has been set, the address will increase by that amount after every read/write. Attempts to read during a write operation or vice-versa will be ignored.
As an example, the following code swaps first four colours of the first palette line (CRAM addresses 0 to 7) with the first four colours of the last palette line (CRAM addresses $60 to $67):
lea ($C00004).l,a5 ; VDP control port lea ($C00000).l,a6 ; VDP data port move.w #$8F02,(a5) ; set auto-increment to 2 (see registers page for explanation) move.l #$00000020,(a5) ; CRAM read at address $0 move.l (a6),d0 ; get first two colours of first palette line move.l (a6),d1 ; get next two colours of first palette line move.l #$00600020,(a5) ; CRAM read at address $60 move.l (a6),d2 ; get first two colours of last palette line move.l (a6),d3 ; get next two colours of last palette line move.l #$C0000000,(a5) ; CRAM write at address $0 move.l d2,(a6) ; set first two colours of first palette line move.l d3,(a6) ; set next two colours of first palette line move.l #$C0600000,(a5) ; CRAM write at address $60 move.l d0,(a6) ; set first two colours of last palette line move.l d1,(a6) ; set next two colours of last palette line
H/V counter
The H/V counter contains the current position of the electron beam on the screen. It consists of two bytes:
- V7-V0: Vertical position.
- H8-H1: Horizontal position. Lowest bit is omitted, so the value appears to be halved.
In interlace double resolution mode, the screen has twice as many scanlines and so the H/V counter is formatted differently:
- V8-V1: Vertical position. Lowest bit is omitted, so the value appears to be halved.
- H8-H1: Horizontal position. Lowest bit is omitted, so the value appears to be halved.
Debug register
The debug register has various effects on VDP operation. Its features are undocumented and not known to be used by any games.
- LSB: Locks the sprite buffer, resulting in some or all sprites becoming invisible.
- PV: 1 = set PSG volume to that of channel CH.
- CH: 00 = square 1; 01 = square 2; 10 = square 3; 11 = noise.
- L0-L1: Force layer visible: 00 = off; 01 = sprites; 10 = plane A; 11 = plane B. (Overrides bit D).
- D: 1 = disable display. Overrides VDP register 01.