![]() |
![]() |
Sega Megadrive Assembly Programming BasicsCopyright, Lewis Bassett, December 2005
Section 2 - CRAM Everything that is drawn onto the screen (by the VDP) is drawn using the colours that are contained in CRAM. CRAM is the part of the VDP's memory where the colour palettes are stored. Remember, just like any other part of the VDP, CRAM can't be accessed directly by the M68000. Instead, we have to write encoded VDP commands to the VDP control port, in order to communicate with the VDP's CRAM. The Megadrive uses four palettes, which each have sixteen colours. Different palettes are used for different parts of the display. For example, most games use one palette for the Plane B, one for Plane A, and two for the sprites. The Megadrive can only draw images using the colours that are defined in CRAM. If a colour isn't in CRAM, then the Megadrive can't use it to draw an image. I'll explain more about this later. So, CRAM contains four palettes, each with sixteen colours. Each of the sixteen colours is defined with one 16-bit value (word), so each palette is 32 bytes. Therefore, the whole of CRAM is 128 bytes in size.
Each colour is displayed by mixing different intensities of red, blue and green light. Therefore, each 16-bit definition contains a blue value, a green value and a red value. The 16-byte definition is made up from four nybbles (hald a byte; one hex digit). Theres a nybble for the blue value, the green value amd the red value. The remaining nybble isn't used. Here's what the word looks like: 0 B G RThe first one, on the far right, is the red value. This is one hex digit (from 0-F) that is used to specifiy the intensity of the red light. The next digit along is the green value, and the last one is the blue value. The remaining nybble is always '0'. Each of the three 'B', 'G' and 'R' nybbles can have one of eight states, represented with the hex digits: '0', '2', '4', '6', '8', 'A', 'C' and 'E'. '0' represents none of that colour's light, and 'E' represents full intensity. By combining the three nybbles, this gives us a choice of 512 possible colours. Here's an example definition: dc.l $0000;In this word, the blue, green and red values are all set to zero, which means the colour is black. Here's another example: dc.l $0eee;This time, the blue, green and red values are all set to full intensity, which makes the colour white. One more example: dc.l $0e0e;This definition has the blue and red values set to full intensity. The green value is zero. This will define the colour purple. Here's a list of colour values, with the actual colour next to them, just as an example of what can be done:
Remember, each palette consists of sixteen of these definitions, and there are four palettes. So it total, CRAM can hold 64 of these 16-bit definitions.
Okay, now we know how to define colours, we can move them into CRAM so that other parts of the VDP can use them to draw graphics. Remember, the M68000 doesn't have direct access to any of the VDP hardware, so in order for us to write to CRAM, we have to send a 32-bit command to the VDP command port, and then send the colour values to the dataport. Unfourtunatly, the way that VDP commands are generated is quite complex. Bits from addresses and settings are jumbled about all over the place. It's literally impossible to generate a VDP command from the top of your head. To get around this, most programmers use special calculators, like Pascal's VDP Register Calculator. Calculators like these can be used to generate a VDP command, based on the parameters that you specify. I've taken a different approach, and have instead written some subroutines that can be called inside a program to generate a VDP command 'on the go'. These subroutines are contained inside the VDPCommands module, that is available in the downloads section of this site.
Simply include the module into your main program with the following line: include "lib\VDPCommands.asm";Note: the 'VDPCommands.asm' module must be first moved into the 'lib\' directory. Inside this module, there's a specific subroutine called 'GetCRAMWriteCommand'. This subroutine generates a VDP command that writes to a specified position, in a specified pallete. Here's how it's used: move.b #$00, d0; Write to the first pallete move.b #$03, d1; At the fourth position bsr GetCRAMWriteCommand; move.l d0, $c00004;The 'GetCRAMWriteCommand' subroutine requires that the number of the pallete to write to is contained in register D0, and the position in that palette to write to is in register D1. When the subroutine has finished, it places the new VDP command into register D0, so that it can be copied into the VDP control port. After the command has been written to the VDP control port, we can now move our 16-bit colour definitions into CRAM. We do this by copying them into the VDP data port, which you'll recall is located at address $C00000. The following example shows how to write some colours into each of the different palettes: move.b #$00, d0; First we'll write to the first pallete move.b #$01, d1; We'll leave the first colour alone, since it's the transparency colour bsr GetCRAMWriteCommand; Generate a VDP command to write to the position in CRAM that we've specified move.l d0, $c00004; Send our new command to the VDP control port, now we can send colours to the VDP data port move.w $0eee, $c00000; Our first colour will be white move.w $0e00, $c00000; The second colour will be blue move.w $0e0e, $c00000; and the third colour will be purple move.b #$01, d0; Now let's move to the second palette move.b #$02, d1; And this time, we'll point to the third colour bsr GetCRAMWriteCommand; Generate a new VDP command move.l d0, $c00004; Write the new command to the VDP data port move.w $0222, $c00000; Our only colour in this palette will be grey move.b #$03, d0; We'll skip the third pallete, but we'll put come colours in the fourth move.b #$00, d1; This time we'll start at the first position bsr GetCRAMWriteCommand; Get a new VDP command move.l d0, $c00004; Send it to the control port move.w $0000, $c00000; Our transparency colour will be black move.w $0eaa, $c00000; the second colour will be light blueNote: in order for the colours to be copied into CRAM properly, the VDP auto increment register must be set, as explained in the previous section. In most cases, all of the palletes will be completely filled up, in which case, the 'GetCRAMWriteCommand' subroutine only needs to be called once. In other cases, individual colours might be changed, in which case the subroutine might be used alot. I'll give you a practical example of setting up the palettes at the end of this chapter, when we'll write a simple graphics demo. |