Zilog Z80

From MegaDrive Wiki
Revision as of 22:48, 6 September 2011 by Tristanseifert (talk | contribs) (Initialise the Z80)
Jump to: navigation, search
The Z80 Sound CPU and Sound RAM on the Model 1 Sega Mega Drive

The Zilog Z80 is a general-purpose 8-bit CPU. It is clocked at 3.58 MHz in the Mega Drive and is often used as the sound CPU, but is officially designated as the Co-Processor to the M68k. It has direct memory access to 8 kilobytes of dedicated sound RAM, as well as the YM2612 FM synthesis chip, and the SN76489 PSG chip. On top of this, it can access a 32KByte 'bank' of any area within M68k memory. This CPU is often used to run the code for the sound driver on many games, while some games only utilise it for DAC playback. The Z80's memory is laid out like the following:

Memory Map

Start End Description
0000h 1FFFh Z80 RAM
2000h 3FFFh Reserved
4000h YM2612 A0
4001h YM2612 D0
4002h YM2612 A1
4003h YM2612 D1
4004h 5FFFh Reserved
6000h Bank register
6001h 7F10h Reserved
7F11h SN76489 PSG
7F12h 7FFFh Reserved
8000h FFFFh M68k memory bank

The current bank to be at the $8000 and up region can be controlled by the banking register.

Programming the Z80

Registers

Seeing as the Z80 was developed to be byte compatible with Intel's 8080 chip, the standard 8080 registers are also present on the Z80:

  • AF: 8-bit accumulator (A) and flag bits (F), and an Add/Subtract flag (usually called N)
  • BC: 16-bit data/address register or two 8-bit registers (A hybrid of an ax and dx register on the M68k)
  • DE: 16-bit data/address register or two 8-bit registers (A hybrid of an ax and dx register on the M68k)
  • HL: 16-bit accumulator/address register or two 8-bit registers
  • SP: stack pointer, 16 bits (This register is also present on the M68k)
  • PC: program counter, 16 bits (This register is also present on the M68k)

The Z80 has these added registers:

  • IX: 16-bit index or base register for 8-bit immediate offsets
  • IY: 16-bit index or base register for 8-bit immediate offsets
  • I: interrupt vector base register, 8 bits
  • R: DRAM refresh counter,
  • AF': alternate (or shadow) accumulator and flags
  • BC', DE' and HL': alternate (or shadow) registers

Initialise the Z80

Before you'll be able to use the Z80, you will need to send it some code to initialise it. Many games do pretty much the same in this department, and this is the code I use in my sound drivers: <source lang="asm">

==============================================================================
Subroutine to initialise the Z80
==============================================================================

Init_Z80: move.w #$100,($A11100)  ; Send the Z80 a bus request move.w #$100,($A11200)  ; Reset the Z80

Init_Z80_WaitZ80Loop: btst #0,($A11100)  ; Has the Z80 reset? bne.s Init_Z80_WaitZ80Loop  ; If not, keep checking.

lea (Init_Z80_InitCode), a0 ; Load the start address of the code to a0. lea ($A00000), a1 ; Load the address of start of Z80 RAM to a1 move.w #Init_Z80_InitCode_End-Init_Z80_InitCode,d1  ; Load the length of the Z80 code to d1

Init_Z80_LoadProgramLoop: move.b (a0)+, (a1)+ ; Write a byte of Z80 data. dbf d1, Init_Z80_LoadProgramLoop ; If we have bytes left to write, write them. move.w #0,($A11200) ; Disable the Z80 reset. move.w #0,($A11100) ; Give the Z80 the bus back. move.w #$100,($A11200) ; Reset the Z80 again. rts ; Return to sub.

Below is the code that the Z80 will execute.

Init_Z80_InitCode: dc.w $AF01, $D91F, $1127, $0021, $2600, $F977 dc.w $EDB0, $DDE1, $FDE1, $ED47, $ED4F, $D1E1 dc.w $F108, $D9C1, $D1E1, $F1F9, $F3ED, $5636 dc.w $E9E9 Init_Z80_InitCode_End: </source>