Howto:Initialise a Mega Drive

Before you can start running your game's program on the Mega Drive, you will need to initialize it first. Initializing a Mega Drive is usually the first thing you do in your code, and involves things such as writing to the TMSS register to activate the VDP, clearing RAM, initializing controller ports, and the Z80. Optionally, you can also initialize some VDP registers for use later in your code, although you may choose to do that again every screen mode.

Contents

Header

Every Mega Drive game has a header at the first 200h bytes of it's ROM. The TMSS checks a specific address in it for the text "SEGA" and then loads your game's code. Early Model 1 Mega Drives do not have a TMSS - but you still need to have "SEGA" in your header. The header's format is like the one below:

The first long in the header is what the CPU will initialize the stack pointer to, and the second long tells it where to start to execute your code. The other entries there should be self explanatory for the different exceptions that can occur, and some games write handlers for them. The rest of the longs that point to 'ErrorTrap' are all unused traps and exceptions, so they point to an endless loop. Note that you must have your 'Hardware system ID' start with 'SEGA' for Model 2 and 3 Mega Drives to load your game.

Once you have your header in place, we can move on to the second part.

Set up Hardware

Before you're able to use the Mega Drive to it's fullest, you will need to set up a few things. First of all, many games will start by checking the 'Port C' of the Mega Drive, which seems to indicate if the console is cold-starting (it was powered on) or if it was reset using the reset button. The ports stay in their current state if the main CPU is reset. When this is the case, games will often not do any setup and jump right into clearing the RAM and then starting the main game loop.

The above code will first check the Port C on the Mega Drive, which will be left in the state it was when the console is reset. Games use this to detect if the game was cold-booted or if the console was reset for some reason. That way, the game will skip clearing RAM and the like if the game was reset. If the game was not reset, it will continue to see if the console has the TMSS, and if it does, write to an area of I/O memory to enable the VDP. It will then go on to clear the VDP's Colour RAM, and then clear main RAM to make sure the game has a clean canvas to work with. Once that's done, it'll initialize the Z80 and you can start your game loop.

Do note that the VDP hasn't been told what to use for registers and the like - you will need to decide what register values you want to use for your game, where you want name tables and the like to be stored, and so on. I'll leave it as an exercise to the reader to figure out how to do that.

Set up the Z80

You might have wondered where Init_Z80 was defined - it goes somewhat like the following: (and can also be found here.)

This basically loads the program into the Z80 and has it execute it, mainly to initialize some stuff.

Interrupts

As you might have noticed in the header, there is a reference to "VBlank" and "HBlank" which are the two types of interrupts the VDP will generate for the M68k. The VBlank routine is called whenever the VDP finished drawing the screen (or when the ray inside a CRT hit the bottom right) and this is where you can fire off DMA queues, load new art, run object's code, and more. The HBlank routine is called when the VDP hits a specific horizontal line on-screen, which is specified by a register. This can be used to re-create the water effect you see in the Mega Drive Sonic games. For now, we don't have any real uses for these routines so we will simply tell them to return to wherever the CPU was previously executing:

VBlank:
rte ; This is like rts, except it ReTurns from Exception, not from a subroutine.
HBlank:
rte ; This is like rts, except it ReTurns from Exception, not from a subroutine.
IllegalInstr:
ZeroDivide:
ChkInstr:
TrapvInstr:
PrivilegeViol:
Trace:
Line1010Emu:
Line1111Emu:
ErrorExcept:
ErrorTrap:
stop #$2700 ; Disable any interrupts and stop the processor

As you can see, there's a rte making these routines not functional. Do note that you always need an rte at the end, and if you change any CPU registers, be sure to back the old ones up to the stack and restore them before your rte.

Conclusion

You should now have a perfectly initialized Mega Drive. Put your program's main loop at MainProgram and code away. There's a few interesting things to know about the Mega Drive when programming it, but that is covered in another howto article.