Actions

SCHG

Difference between revisions of "VDP Documentation/General/Ports"

From Sonic Retro

m (Text replacement - "<asm>" to "<syntaxhighlight lang="asm">")
 
Line 1: Line 1:
__NOTOC__
+
#redirect [[sega:Sega Mega Drive/VDP general usage]]
{{SCHG VDP}}
 
The main [[Mega Drive]] processor (the [[Motorola 68000]]) cannot directly access VDP memory areas. Instead, it communicates with the VDP through '''ports'''.
 
 
 
== Memory map ==
 
The addresses for the VDP ports are shown exhaustively below, though only $C00000 and $C00004 are used generally.
 
{| class="prettytable"
 
! 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 || HV counter (read-only)
 
|-
 
| $C0000A || B/W || HV counter (read-only, mirror)
 
|-
 
| $C0000C || B/W || HV counter (read-only, mirror)
 
|-
 
| $C0000E || B/W || HV 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 || Unused mystery port
 
|}
 
 
 
== Control port ==
 
The control port, as the name suggests, allows the 68000 to control VDP memory access. Additionally, it also allows the reading of VDP status and the setting of registers. The control port is accessed at address $C00004 from the 68000.
 
 
 
=== Getting VDP status ===
 
Reading the control port returns a VDP status word, which has the following format, counting from the least significant bit:
 
 
 
{| class="prettytable"
 
! Bit !! Description
 
|-
 
| 0 || This is 0 if the VDP is in NTSC mode, and 1 if it's in PAL mode.
 
|-
 
| 1 || This is set for the duration of a DMA operation. It is only useful for fills and copies, as the 68000 is frozen for transfers from 68000 memory to VDP.
 
|-
 
| 2 || Set during horizontal blanking.
 
|-
 
| 3 || Set during vertical blanking.
 
|-
 
| 4 || Set when the odd frame is being displayed in interlaced mode, clear otherwise.
 
|-
 
| 5 || Set when any two sprites have non-transparent pixels overlapping each other. Its usefulness is quite limited however since it cannot be determined which two sprites collided and where.
 
|-
 
| 6 || Set when there are too many sprites on a scan line i.e. over 17 in 32-cell mode or over 21 in 40-cell mode.
 
|-
 
| 7 || Set when a vertical interrupt occurs, presumably cleared at the end of a frame.
 
|-
 
| 8 || FIFO full flag. The VDP has a FIFO which can hold up to 4 words while the VDP's busy and unable to immediately process the write command. This flag is set when the 4th word is written and the FIFO cannot hold any more data. If the 68000 attempts to write again it will be frozen until at least one of the stored words has been delivered to its destination.
 
|-
 
| 9 || FIFO empty flag. This flag is only set when the FIFO is completely empty. If the FIFO is only partially filled both this flag and the FIFO full flag are 0.
 
|-
 
| 10 || Unused (always set).
 
|-
 
| 11 || Unused (always cleared).
 
|-
 
| 12 || Unused (always set).
 
|-
 
| 13 || Unused (always set).
 
|-
 
| 14 || Unused (always cleared).
 
|-
 
| 15 || Unused (always cleared).
 
|}
 
 
 
=== Writing to registers ===
 
The VDP has 24 write-only registers, each taking bytes, the purpose of which is explained [[SCHG:VDP Documentation/General/Registers|here]]. A register can be set by writing a word to the control port, which has the following format:
 
 
 
{| class="prettytable" style="margin-left: auto; margin-right: auto; text-align: center"
 
! style="width: 6.25%" | 15
 
! style="width: 6.25%" | 14
 
! style="width: 6.25%" | 13
 
! style="width: 6.25%" | 12
 
! style="width: 6.25%" | 11
 
! style="width: 6.25%" | 10
 
! style="width: 6.25%" | 9
 
! style="width: 6.25%" | 8
 
! style="width: 6.25%" | 7
 
! style="width: 6.25%" | 6
 
! style="width: 6.25%" | 5
 
! style="width: 6.25%" | 4
 
! style="width: 6.25%" | 3
 
! style="width: 6.25%" | 2
 
! style="width: 6.25%" | 1
 
! style="width: 6.25%" | 0
 
|-
 
| 1 || 0 || 0 || RS4 || RS3 || RS2 || RS1 || RS0 || D7 || D6 || D5 || D4 || D3 || D2 || D1 || D0
 
|}
 
 
 
Bits 15 and 14 are always 1 and 0 respectively to differentiate register writes from access control writes. RS4-RS0 is the register number, from $00 to $17 (writing to registers $18-$1F has no effect), and D7-D0 is the data to write. Since the VDP treats longword access as equivalent to two word accesses, two registers can be programmed at the same time by writing a longword:
 
 
 
<syntaxhighlight lang="asm"> move.l #$80048134,($C00004).l ; set register 0 to $04 and register 1 to $34</syntaxhighlight>
 
 
 
=== Setting VDP access ===
 
The 68000 can set VDP access by writing a longword to the control port, which has the following format:
 
 
 
{| class="prettytable" style="margin-left: auto; margin-right: auto; text-align: center"
 
! style="width: 6.25%" | 31
 
! style="width: 6.25%" | 30
 
! style="width: 6.25%" | 29
 
! style="width: 6.25%" | 28
 
! style="width: 6.25%" | 27
 
! style="width: 6.25%" | 26
 
! style="width: 6.25%" | 25
 
! style="width: 6.25%" | 24
 
! style="width: 6.25%" | 23
 
! style="width: 6.25%" | 22
 
! style="width: 6.25%" | 21
 
! style="width: 6.25%" | 20
 
! style="width: 6.25%" | 19
 
! style="width: 6.25%" | 18
 
! style="width: 6.25%" | 17
 
! style="width: 6.25%" | 16
 
|-
 
| CD1 || CD0 || A13 || A12 || A11 || A10 || A9 || A8 || A7 || A6 || A5 || A4 || A3 || A2 || A1 || A0
 
|-
 
! style="width: 6.25%" | 15
 
! style="width: 6.25%" | 14
 
! style="width: 6.25%" | 13
 
! style="width: 6.25%" | 12
 
! style="width: 6.25%" | 11
 
! style="width: 6.25%" | 10
 
! style="width: 6.25%" | 9
 
! style="width: 6.25%" | 8
 
! style="width: 6.25%" | 7
 
! style="width: 6.25%" | 6
 
! style="width: 6.25%" | 5
 
! style="width: 6.25%" | 4
 
! style="width: 6.25%" | 3
 
! style="width: 6.25%" | 2
 
! style="width: 6.25%" | 1
 
! style="width: 6.25%" | 0
 
|-
 
| 0 || 0 || 0 || 0 || 0 || 0 || 0 || 0 || CD5 || CD4 || CD3 || CD2 || 0 || 0 || A15 || A14
 
|}
 
 
 
A15-A0 is the destination RAM address. CD5 is the DMA flag, and CD4 is set for a VRAM copy DMA operation. Bits CD3-CD0 govern the type of access:
 
 
 
{| class="prettytable" style="text-align: center"
 
! Access type !! CD3 !! CD2 !! CD1 !! CD0
 
|-
 
| VRAM read  || 0 || 0 || 0 || 0
 
|-
 
| VRAM write  || 0 || 0 || 0 || 1
 
|-
 
| CRAM read  || 1 || 0 || 0 || 0
 
|-
 
| CRAM write  || 0 || 0 || 1 || 1
 
|-
 
| VSRAM read  || 0 || 1 || 0 || 0
 
|-
 
| VSRAM write || 0 || 1 || 0 || 1
 
|}
 
 
 
== Data port ==
 
After VDP access has been set, data can be read or written through the data port, which is accessed at address $C00000 from the 68000. After each read or write, the address is increased by the value of the auto increment register (register $0F). Attempting to read data after setting up a write operation or vice-versa will cause the read or write to 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):
 
 
 
<syntaxhighlight lang="asm"> 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</syntaxhighlight>
 
 
 
== H/V counter ==
 
 
 
The H/V counter is a read-only port which can be accessed at address $C00008 from the 68000. It keeps track of the position of the TV beam and its value is only meaningful in active scan (i.e. not during vertical blank).
 
 
 
Reading the port will lead to a 2 byte value: the low byte is the horizontal position of the beam and the high byte is the vertical position. Under H40 or interlaced modes, values may be bigger than 255 and hence don't fit. Because of this, the LSB of the vertical counter is replaced by the MSB in interlaced mode, and the LSB of the horizontal counter is always dropped (so it'll have half the real value).
 
 
 
 
 
{{SCHGuides}}
 
[[Category:Sonic Community Hacking Guide|{{PAGENAME}}]]
 

Latest revision as of 17:41, 16 June 2018