codeslinger.co.uk

Sega Master System - The Hardware.

The Hardware:

Before we begin with the emulation it would be an idea to have a glimpse of the hardware so you can see what you're letting yourself in for.

There are four main devices we will be emulating.

Timing:

In order for our emulator to have a decent compatibility it is vitally important that the three main chips (processor, vdp and sound) synchronise correctly. This will be controlled via knowing how many machine clicks the SMS could perform a second, and knowing how many Z80 clock cycles each instruction takes. Combining this together we can get our Z80 to execute the same number of instructions per second as the real SMS. The key to all this is knowing how many Z80 clock cycles the last emulated instruction took and then we can convert this to SMS machine clicks and then convert it to the VDP chip clock cycles and finally the sound chip clock cycles.

The main clock in the SMS runs at 10.738580 MHz. Which is 10738580 machine clicks every second. The Z80 processor runs at a third of the speed of the main clock (3.58 MHz). The VDP runs at half the speed of the main clock (5.36 MHz). The sound clock runs at the same speed as the Z80 processor (3.58 MHz).

There is one final piece of information you need to arm yourself with before you are ready to create the main emulation loop is that the VDP refreshes its screen 60 times a second. This means that every second the screen gets drawn 60 times. Therefore if the main clock executes 10738580 machine clicks every second then every frame of the VDP 10738580/60 machine clicks is executed. So our emulator also needs to execute 60 frames a second but because our PCs are now much faster than the SMS we need to slow our emulation loop down so the games play at the correct speed. This is quite easy to do. If we code our main emulation loop to emulate one frame at a time then after it has finished emulating a frame it waits until 1/60th of a second has passed until it can emulate the next frame. By doing it this way our emulator will draw exactly 60 frames every second. This means our main emulation loop looks like this (I'll use pseudocode for now):

void Emulator::MainLoop( )
{
  const double SIXTYTH = 1000/60 ; // we're working in milliseconds
  double lastFrameTime = 0 ;
  while (notQuitting) // loop until the player quits
  {
   double currentTime = getCurrentTime( ) ;

   // draw a frame every 1/60 of a second
   if ((lastFrameTime + SIXTYTH) <= currentTime)
   {
    lastFameTime = currentTime ;
    Update( ) ; // this will draw one frame
   }
  }
}


// this is responsible for emulating one frame
void Emulator::Update( )
{
  const double MACHINE_CLICKS_PER_FRAME = 10738580 / 60 ;
  unsigned int clicksThisUpdate = 0 ;

  // emulate 1/60th of a seconds amount of machine clicks
  while (clicksThisUpdate < MACHINE_CLICKS_PER_FRAME)
  {
   int z80ClockCycles = m_Z80.ExecuteNextInst();

   // the machine clock is 3 times faster than the z80 clock
   int machineClicks = z80ClockCycles * 3 ;

   // the vdp clock is half the speed of the machine clock
   float vdpCycles = machineClicks / 2 ;

   // the sound clock is the same speed as the z80
   int soundCycles = z80ClockCycles ;

   m_VDP.Update(vdpCycles) ;
   m_Sound.Update(soundCycles) ;

   clicksThisUpdate += machineClicks ;
  }
}

The above code shows how the three main chips can be synchronised with each other. You will notice that the type of VDP cycles is a float not an integer. This is so we dont lose any accuracy over time with the emulation of the VDP.

Ports:

The way that the games communicate with the four main devices is by using the Z80 instructions IN and OUT. These instructions purpose is to talk to the main four devices. The four devices will have port numbers where reading and writing of data bytes pass through. So for example the following Z80 instruction "INA 0x7e" reads port 0x7E and puts its return value into register A. I will talk about this more later in the tutorials. All you need to know for now is that reading and writing to the four main devices is done through ports.

The following is a break down of which port numbers map to which device:

0x7E : Reading: returns VDP V counter. Writing: writes data to Sound Chip
0x7F : Reading: returns VDP H counter. Writing: writes data to Sound Chip (mirror of above)
0xBE : Reading: reads VDP data port: Writing: writes vdp data port
0xBF : Reading: Gets VDP statis: Writing: writes to vdp control port
0xDC : Reading: Reads joypad 1. Writing: cannot write to
0xDD : Reading: Reads joypad 2. Writing: cannot write to

Port 0xBD does the same as port 0xBF. Port 0xC0 does the same as 0xDC and finally port 0xC1 does the same as 0xDD

So now you know how to control the execution of the devices and a basic understanding of how the games interact with them. I will delve a lot deeper into working with the ports in later sections of these tutorials. For now it is time to move on and get started with the SMS emulation.