Difference between revisions of "VDP"

From MegaDrive Wiki
Jump to: navigation, search
(Calculating VRAM Addresses)
(Calculating VRAM Addresses)
Line 713: Line 713:
 
! 2
 
! 2
 
! 1
 
! 1
!  
+
! Byte 2
 
! 128
 
! 128
 
! 64
 
! 64
Line 722: Line 722:
 
! 2
 
! 2
 
! 1
 
! 1
!  
+
! Byte 3
 
! 128
 
! 128
 
! 64
 
! 64
Line 731: Line 731:
 
! 2
 
! 2
 
! 1
 
! 1
!  
+
! Byte 4
 
! 128
 
! 128
 
! 64
 
! 64
Line 749: Line 749:
 
| align="center" | A
 
| align="center" | A
 
| align="center" | A
 
| align="center" | A
| Byte 2
+
|
 
| align="center" | A
 
| align="center" | A
 
| align="center" | A
 
| align="center" | A
Line 758: Line 758:
 
| align="center" | A
 
| align="center" | A
 
| align="center" | A
 
| align="center" | A
| Byte 3
+
|
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
Line 767: Line 767:
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
| Byte 4
+
|
 
| align="center" | M
 
| align="center" | M
 
| align="center" | M
 
| align="center" | M
Line 843: Line 843:
 
! 2
 
! 2
 
! 1
 
! 1
!  
+
! Byte 2
 
! 128
 
! 128
 
! 64
 
! 64
Line 852: Line 852:
 
! 2
 
! 2
 
! 1
 
! 1
!  
+
! Byte 3
 
! 128
 
! 128
 
! 64
 
! 64
Line 861: Line 861:
 
! 2
 
! 2
 
! 1
 
! 1
!  
+
! Byte 4
 
! 128
 
! 128
 
! 64
 
! 64
Line 879: Line 879:
 
| align="center" | 1
 
| align="center" | 1
 
| align="center" | 1
 
| align="center" | 1
| Byte 2
+
|
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
Line 888: Line 888:
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
| Byte 3
+
|
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
Line 897: Line 897:
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
| Byte 4
+
|
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0
 
| align="center" | 0

Revision as of 18:55, 6 September 2011

The VDP in a Model 1 Genesis.The VRAM is visible near the bottom left, and the M68k to Z80 IO chip near the top.

The VDP, also known as Video Display Processor, handles all video output on the Mega Drive. The VDP is often known as the YM7101, which is derived from the Sega Master System VDP for backwards compatibility. The Master System VDP is in turn derived from the Texas Instruments TMS9918A. In most (if not all) Mega Drive models, the VDP is a dedicated large chip on the main motherboard.

It has 64 KB of VRAM, which can be used to store patterns (also known as art) plane and sprite name tables, as well as horizontal scroll data. The benefit of storing name tables and H-Scroll in VRAM is that you can decide where this data is stored, but leaves less room for art. The VDP has 64 bytes of 9-bit RAM to store palettes. This special area of the VDP is known as CRAM, or Colour RAM.

The VDP has the capability of displaying up to 80 sprites on-screen, as well as the A and B planes, and the Window plane. The window plane can be used as a replacement for the A plane in some circumstances. It can also support 64 on-screen colours at any time, as well as scrolling the entire screen or specific parts of it horizontally and vertically. There is also multiple registers that control how the VDP is configured, which are written to the control word as 16-bit words.

Accessing the VDP

To access the VDP, you must use a special area of I/O memory. Below is a map of the VDP's IO memory, starting at $C00000:

$C00000 Data Port
$C00002 Data Port (Mirror)
$C00004 Control Port
$C00006 Control Port (Mirror)
$C00008 H/V Counter
$C0000A H/V Counter (Mirror)
$C0000C H/V Counter (Mirror)
$C0000E H/V Counter (Mirror)
$C00011 SN76489 PSG
$C00013 SN76489 PSG (Mirror)
$C00015 SN76489 PSG (Mirror)
$C00017 SN76489 PSG (Mirror)

In most occasions, the only parts of the VDP you'll be interested in are the control and data ports, as well as the PSG. The control and data ports are word-wide, but they are mirrored to allow for more efficient long-writes, which lets you program two registers in one instruction, write more art per instruction, and so on, The H/V counter I'm not sure on - I however do know it will tell you the position of the cathode ray inside your TV, or what pixel the VDP is currently drawing. Lastly, you can access the PSG chip. The reason for this being in the VDP address space is that the PSG is actually integrated into the VDP! If you look at the traces on your MD motherboard, you can see that one pin leads to the audio mixing circuit.

VDP Registers

The VDP has 25 registers, of which you can program 24 through code. Some registers do not seem to do anything and are not documented anywhere, but that doesn't mean you shouldn't be afraid to try. The last register isn't a register that is written, but you read back the VDP control to a CPU register or work RAM, you can get various information about the current state of the VDP. Many registers are also programmed as bitfields - meaning you should be able to set individual bits, and then write the final hex number to the VDP control port.

All register values are written to the control port as a word - the first byte being the register number added to $80, and the second byte being the value.

In the tables below, any bits shown as 0 will always be 0, and any values shown as 1 will always be 1. Bits that change something have a letter assigned to them that is explained below the table.

Register 00 - Mode Register 01
128 64 32 16 8 4 2 1
0 0 0 IE1 0 1 HV 0

The state of the bit IE1 decides whether the VDP will generate a horizontal interrupt for every nth scanline, or not. This is a level 4 interrupt for the M68k. A 1 means it is enabled, while 0 means it is disabled. The state of HV lets you 'latch' the contents of the HV counter. If it is set to 1, the VDP will stop modifying the counter so you can read it and calculate things, while when set to 0, the VDP will actively update the counter.

Register 01 - Mode Register 02
128 64 32 16 8 4 2 1
0 DE IE0 X Y 1 0 0

DE decides if the display is enabled (1) or disabled (0). This is useful to perform quick art loading. IE0 enables the vertical blank interrupt, or VBI. This is a Level 6 interrupt to the M68k. X allows DMA to be performed when set, while it disables any sort of DMA when it is not set. Y sets the display mode. When set to 1, 30 cell mode is enabled, which is exclusive to PAL. When set to 0, 28 cell mode is enabled, which is always the case on NTSC.

Register 02 - Plane A Name Table Location
128 64 32 16 8 4 2 1
0 0 X X X 0 0 0

XXX is the VRAM location of the name table for Plane A divided by 400h. This means that your Plane A name table has to be located at a VRAM address that's a multiple of 400h. If you want your plane A name table to be located at C000h in VRAM, divide that by 400h, giving you the result to write to the VDP register, 30h.

Register 03 - Window Name Table Location
128 64 32 16 8 4 2 1
0 0 X X X 0 0 0

XXX is the VRAM location of the name table for the Window Plane divided by 400h. This means that your Window Plane name table has to be located at a VRAM address that's a multiple of 400h. If you want your window plane name table to be located at F000h in VRAM, divide that by 400h, which gives you 3Ch, which is what you'd write to this register.

Register 04 - Plane B Name Table Location
128 64 32 16 8 4 2 1
0 0 0 0 0 X X X

XXX is the VRAM location of the name table for Plane B divided by 2000h. This means that your Plane B name table has to be located at a VRAM address that's a multiple of 2000h. If you want the plane B name table to be stored at E000h in VRAM, divide that by 2000h, which gives you 07h, which is the value you'd write to this register.

Register 05 - Sprite Attribute Table Location
128 64 32 16 8 4 2 1
0 X X X X X X X

XXXXXXX is the VRAM location of the sprite attribute table divided by 200h. This means that your sprite attribute table has to be located at a VRAM address that's a multiple of 200h. The lower limit of the location multiple means you can squish between unused space for mappings, and so on. Say you want your sprite attribute table to be located at D800h in VRAM, divide this by 200h and write 6Ch to this register.

Register 06 - Unused/Unknown
128 64 32 16 8 4 2 1
0 0 0 0 0 0 0 0

This is one of these odd unused registers that aren't documented anywhere to my knowledge. Many, if not all games don't touch these registers. Don't hesitate to edit this page if you have info about one of these, though.

Register 07 - Backdrop Colour
128 64 32 16 8 4 2 1
0 0 X X Y Y Y Y

XX is the palette line from where the backdrop colour is to be retrieved from, while YYYY is the entry in that palette to use. Do note that the colour you declared as the transparent colour can be displayed. For example, if you want to use colour 2 of palette line 2, you'll write 11h to this register.

Register 08 - Unused/Unknown
128 64 32 16 8 4 2 1
0 0 X X Y Y Y Y

This is one of these odd unused registers that aren't documented anywhere to my knowledge. Many, if not all games don't touch these registers. Don't hesitate to edit this page if you have info about one of these, though.

Register 09 - Unused/Unknown
128 64 32 16 8 4 2 1
0 0 X X Y Y Y Y

This is one of these odd unused registers that aren't documented anywhere to my knowledge. Many, if not all games don't touch these registers. Don't hesitate to edit this page if you have info about one of these, though.

Register 10 - Horizontal Interrupt
128 64 32 16 8 4 2 1
H H H H H H H H

HHHHHHHH is what scanline you want your horizontal interrupt to be called on. For this to take any effect, make sure you enabled horizontal interrupts in register 0's IE1, and that you are not blocking interrupts on the M68k side.

Register 11 - Mode Register 3
128 64 32 16 8 4 2 1
0 0 0 0 IE2 VS HS1 HS2

IE2 controls external interrupts that are raised by the TH pin on one of the three IO ports. This is how almost all light guns function. When the trigger is depressed, they pull TH high which causes the game's external interrupt routine to run. This is a Level 2 interrupt on the M68k side. VS controls vertical scrolling. When set to 0, the entire screen is scrolled by one longword in VSRAM. When set to 1, every word in VSRAM vertically scrolls two cells, or tiles of art. HS1 and HS2 both control horizontal scrolling. When set to 00, the entire screen is scrolled at once by one longword in the horizontal scroll table. Setting 01 is prohibited, and may cause undefined behaviour. When set to 10, every long scrolls 8 pixels, and when set to 11, every longword scrolls one scanline.

Register 12 - Mode Register 4
128 64 32 16 8 4 2 1
RS0 0 0 0 SHI LSM1 LSM0 RS1

RS0 and RS1 should be set to the same value, seeing as they control the same thing. When set to 0, the VDP is using horizontal 32 tile mode. When set to 1, the VDP will use a 40 tile wide display. SHI enables shadow/highlight, a special mode to allow for more colours on-screen when set. LSM1 and LSM0 control interlace settings: 00 sets no interlace, 01 enables interlace, 10 is prohibited, and 11 interlaces at double resolution. Sonic 2 and some other games use the latter interlace mode for their dual-player split screen.

Register 13 - HScroll Data Location
128 64 32 16 8 4 2 1
0 0 X X X X X X

XXXXXX controls where the HScroll data, if at all, is stored. This location has to be a multiple of 400h. For example, if your HScroll data is located at DC00h, you will divide that by 400h to get 37h.


Register 14 - Unused/Unknown
128 64 32 16 8 4 2 1
0 0 X X Y Y Y Y

This is one of these odd unused registers that aren't documented anywhere to my knowledge. Many, if not all games don't touch these registers. Don't hesitate to edit this page if you have info about one of these, though.

Register 15 - Auto-Increment Value
128 64 32 16 8 4 2 1
X X X X X X X X

XXXXXXXX sets the 8-bit value to add after a VRAM access. This is incredibly useful for writing art to the VDP control port, as you can write a word, and the VDP will automagically increase the VRAM pointer for you. Many games set this to 2.

Register 16 - Plane Size
128 64 32 16 8 4 2 1
0 0 X X 0 0 Y Y

XX sets the size of the vertical size of both the A and B planes. When set to 00, you will get a 32 tile vertical size, 01 sets 64 tile vertical, and 11 sets 128 vertical tile size. Setting 10 is prohibited and may cause undefined behaviour. YY sets the size of the horizontal size of both the A and B planes. When set to 00, you will get a 32 tile horizontal size, 01 sets 64 tile horizontal, and 11 sets 128 horizontal tile size. Setting 10 is prohibited and may cause undefined behaviour.

It is important to know that a name table can never exceed 8192 bytes. While a 64x64 or 128x32 name table is valid, a 128x128 or 64x128 name table is not valid.

Register 17 - Window Plane Horizontal Position
128 64 32 16 8 4 2 1
D 0 0 X X X X X

D sets the direction in which to move the window plane horizontally - 0 means to the left, while 1 means to the right. XXXXX sets how many cells to move the window plane horizontally in the direction specified by D.

Register 18 - Window Plane Vertical Position
128 64 32 16 8 4 2 1
D 0 0 X X X X X

D sets the direction in which to move the window plane vertically - 0 means up, while 1 means down. XXXXX sets how many cells to move the window plane vertically. in the direction specified by D.

An important feature to know about the window plane is that it masks plane A, even transparent pixels. This makes it unsuitable for use in many circumstances, but some games use it as a HUD.

Register 19 and 20 - DMA Length
128 64 32 16 8 4 2 1 Register 20 128 64 32 16 8 4 2 1
X X X X X X X X Y Y Y Y Y Y Y Y

XXXXXXXX is the low byte of the DMA length. YYYYYYYY is the high byte of the DMA length.

If the DMA length is set to 0, the VDP will treat it as FFFFh, which will cause lots of issues.

Register 21, 22 and 23 - DMA Source
128 64 32 16 8 4 2 1 Register 22 128 64 32 16 8 4 2 1 Register 23 128 64 32 16 8 4 2 1
X X X X X X X X Y Y Y Y Y Y Y Y M1 M2 Z Z Z Z Z Z

XXXXXXXX is the low byte of the DMA source address. YYYYYYYY is the middle byte of the DMA source address. ZZZZZZ is the high byte of the DMA source address. M1 and M2 tell the VDP what type of DMA shall be coming up - 0Z means that whatever is referenced in these 3 registers is copied to the VRAM. 01 means VRAM fill, and 11 means VRAM copy. 10 is not documented anywhere and seems to be prohibited. More about these DMA modes can be found here.

The next register in the sense that you can program it as it is read only. To obtain the information contained within it, read a 16-bit word from the control port.

VDP Status Register
128 64 32 16 8 4 2 1 Byte 2 128 64 32 16 8 4 2 1
0 0 1 1 0 1 F1 F2 VIP SO SC OF VB HB DMA PAL

F1 and F2 indicate the status of the FIFO - when F1 is set, the FIFO is empty. When F2 is set, the FIFO is full. The FIFO can hold 4 16-bit words for the VDP to process. If the M68k attempts to write one more word once full is raised, it will be frozen until the first word can be delivered. If the FIFO has items in it, both bits will be clear. VIP indicates that a vertical interrupt occurs, approximately at line E0h. It seems to be cleared at the end of the frame. SO is set when there are too many sprites on the current scanline. The 17th sprite in 32 cell mode and the 21st sprite on one scanline in 40 cell mode will cause this. SC is set when any sprites have non-transparent pixels overlapping. This is likely cleared at the end of the frame. OF is set if the display is interlaced, and if the display is currently in the odd frame. VB returns the real-time status of the V-Blank signal. It is presumably set on line E0h and unset at FFh. HB returns the real-time status of the H-Blank signal. DMA is set for the duration of a DMA operation. This is only useful for fills and copies, since the M68k is frozen during M68k to VRAM transfers. PAL seems to be set when the system's display is PAL, and possibly reflects the state of having 240 line display enabled. The same information can be obtained from the version register.

Calculating VRAM Addresses

To access the VRAM, you need to tell the VDP where exactly you want to write to. Calculation of these values is slightly tricky at first due to the nature of the VDP.

Calculate a VRAM Address
128 64 32 16 8 4 2 1 Byte 2 128 64 32 16 8 4 2 1 Byte 3 128 64 32 16 8 4 2 1 Byte 4 128 64 32 16 8 4 2 1
M M A A A A A A A A A A A A A A 0 0 0 0 0 0 0 0 M M M M 0 0 A A

For now, ignore any bits that are set to 0 in the table above. First, let's start off by figuring out what value to put for the A's. If you wanted to write to the VRAM address AC80h, you would first convert this into bits, which would leave you with the following:


128 64 32 16 8 4 2 1 Byte 2 128 64 32 16 8 4 2 1
1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0

The M's will control the mode of where you will write to or read from. They work as following:

  • If all M's are 0, then VRAM read mode is set.
  • If M's 1 to 5 are 0, but R 0 is 1, then VRAM write mode is set.
  • If M's 0, 1, 2, 4 and 5 are 0, but R 3 is 1, then CRAM read mode is set.
  • If M's 2 to 5 are 0, but R's 0 and 1 are 1, then CRAM write mode is set.
  • If M's 0, 1, 3, 4 and 5 are 0, but R 2 is 1, then VSRAM read mode is set.
  • If M's 1, 3, 4 and 5 are 0, but R's 0 and 2 are 1, then VSRAM write mode is set.

Now, if we continue with the example above of writing to AC80h, your final value will leave you with something like this:

VRAM Write to AC80h
128 64 32 16 8 4 2 1 Byte 2 128 64 32 16 8 4 2 1 Byte 3 128 64 32 16 8 4 2 1 Byte 4 128 64 32 16 8 4 2 1
0 1 1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Now, simply convert this to hexadecimal to get the final value of 6B200000h. Writing and reading to the various areas of the VDP's memory space is now a piece of cake. To write to CRAM, an easy trick is to remember C0000000h, where the C stands for Colour or CRAM.

DMA

The VDP has an interesting little feature called DMA, or Direct Memory Access. This is nothing new - many computers and other devices have this as well to move data faster without requiring the CPU to do it. As explained in the registers section above, the VDP has the capability of doing 3 different DMA types - M68k to VRAM, VRAM Fill and VRAM copy. Something important to note is that during M68k to VRAM transfers, as the VDP will have the bus, the M68k will be frozen by the VDP for the duration of the DMA transfer. Thankfully, the speed advantage of DMA over manually writing art in a loop is worth the lost execution time, as long as the DMA is done during VBlank or when the display is enabled. During HBlank, the speed of DMA is about the same as the speed of a art loading loop running on the M68k. Do note that the Z80 will keep running during DMA, unless it attempts to access the bus, at which point it will also be frozen for the duration of the DMA transfer.

To set up a DMA, you must set the DMA registers (19-23). For DMA to work, you will need to enable DMA in register 1, as well as set the auto-increment register (15) to 2. The VDP will then transfer the data at the fastest speed possible to it's memory, and then resume the M68k.

A VRAM Fill will 'fill' will fill another VRAM address with data from an even VRAM address. I have no idea what this could be used for, but for some reason this mode exists. This applies to only VRAM, not CRAM or VSRAM. The last DMA mode is VRAM Copy - it will copy from the source address to the destination address, for as many bytes as the length register indicates. I'm not sure why this mode exists, either. These two modes don't freeze the M68k, but it is important that you only read the VDP status register, H/V counter, and write to the PSG registers. Doing otherwise may corrupt VRAM and VDP registers.

The table below illustrates the VDP's DMA capacity for all three modes during different times:

VDP DMA Capacity
DMA Mode Screen Width Display Period Transfer Capacity
M68k to VRAM 32 cells Active 16
Blanking 167
40 cells Active 18
Blanking 205
VRAM Fill 32 cells Active 15
Blanking 166
40 cells Active 17
Blanking 204
VRAM Copies 32 cells Active 8
Blanking 83
40 cells Active 9
Blanking 108

Blanking indicates a V-Blank, or times when the display is forcibly blanked through the use of register 1. The values in the "Transfer Capacity" column indicate bytes, except if the DMA Mode is M68k to VRAM and the destination is CRAM or VSRAM.

Often times, games will create a DMA queue that will hold a specific number of entries to DMA on the next vertical blank interrupt, where it will be processed. See the howto article on this to learn about making one.

Patterns

Patterns are little 8x8 pieces of art that can be displayed in any of the 4 available palettes. Each pattern is 20h bytes in length, and is stored anywhere in VRAM. They are mapped to the display through the use of the plane maps, which can also set the palette line for them to use, as well as the high priority flag. Many games store their patterns compressed in their ROMs for a number of reasons, mainly the fact to save ROM space. Some games will decompress them to RAM and DMA from there, while others will simply just write to the VDP. While the first is faster, it might not be the right option if it has the possibility of corrupting RAM.

Name Tables

Name Tables will tell the VDP what to draw, and where to draw it. Essentially, they map patterns to the different planes you can have on-screen at any given time. As mentioned before, these name tables can never exceed 8KBytes in size. Some games will compress these, but in some cases, for example, if scrolling credits are needed and so is tile reloading, compression can often be a hassle unless it is able to decompress only a specific range of bytes. RLE compression often works very well for compressing name tables. If you scroll past the end of a name table, it will wrap again. Some games will use this to have scrolling credits.

Shadow/Highlight

Shadow/Highlight is a special VDP mode that allows you to choose from more colours to display on-screen, about 3 times as much as the normal 512. Background tiles will be shown at half intensity, or normal intensity if their priority flag is set. If you do set the priority flag for a background tile, it seems as if the foreground and any other art passing through that area will also be affected by this and will be drawn at regular intensity. Depending on the sprite's priority setting, they are also either shown at half intensity, or regular intensity. Colours 0Eh, 1Eh, and 2Eh are always shown at regular intensity for some reason, most likely due to a bug in the VDP itself. Any pixels in a sprite that use the colour 3Eh and 3Fh are treated specially. Pixels with the colour 3Eh are not drawn, but instead, the background beneath that pixel will be drawn at half intensity. Pixels with the colour of 3Fh are not drawn either, but the underlying pixels will be drawn at double intensity.

I'm not sure how the VDP figures out these colours, but it seems that half and double intensity colors are half and double brightness of the current palette.