2900 lines
152 KiB
HTML
2900 lines
152 KiB
HTML
|
<html><head>
|
|||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|||
|
<title>Specifications</title>
|
|||
|
<meta name="GENERATOR" content="nocash XED2HTM converter">
|
|||
|
</head><body link="#0033cc" alink="#0033cc" bgcolor="#ffffff" text="#000000" vlink="#0033cc">
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="pandocs"></a><font size="+2"> Pan Docs</font></td></tr></tbody></table><br>
|
|||
|
<b>Overview<br>
|
|||
|
</b><a href="#aboutthepandocs">About the Pan Docs</a><br>
|
|||
|
<a href="#gameboytechnicaldata">Game Boy Technical Data</a><br>
|
|||
|
<a href="#memorymap">Memory Map</a><br>
|
|||
|
<br>
|
|||
|
<b>I/O Ports<br>
|
|||
|
</b><a href="#videodisplay">Video Display</a><br>
|
|||
|
<a href="#soundcontroller">Sound Controller</a><br>
|
|||
|
<a href="#joypadinput">Joypad Input</a><br>
|
|||
|
<a href="#serialdatatransferlinkcable">Serial Data Transfer (Link Cable)</a><br>
|
|||
|
<a href="#timeranddividerregisters">Timer and Divider Registers</a><br>
|
|||
|
<a href="#interrupts">Interrupts</a><br>
|
|||
|
<a href="#cgbregisters">CGB Registers</a><br>
|
|||
|
<a href="#sgbfunctions">SGB Functions</a><br>
|
|||
|
<br>
|
|||
|
<b>CPU Specifications<br>
|
|||
|
</b><a href="#cpuregistersandflags">CPU Registers and Flags</a><br>
|
|||
|
<a href="#cpuinstructionset">CPU Instruction Set</a><br>
|
|||
|
<a href="#cpucomparisionwithz80">CPU Comparision with Z80</a><br>
|
|||
|
<br>
|
|||
|
<b>Cartridges<br>
|
|||
|
</b><a href="#thecartridgeheader">The Cartridge Header</a><br>
|
|||
|
<a href="#memorybankcontrollers">Memory Bank Controllers</a><br>
|
|||
|
<a href="#gamegeniesharkcheats">Gamegenie/Shark Cheats</a><br>
|
|||
|
<br>
|
|||
|
<b>Other<br>
|
|||
|
</b><a href="#powerupsequence">Power Up Sequence</a><br>
|
|||
|
<a href="#reducingpowerconsumption">Reducing Power Consumption</a><br>
|
|||
|
<a href="#spriterambug">Sprite RAM Bug</a><br>
|
|||
|
<a href="#externalconnectors">External Connectors</a><br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="aboutthepandocs"></a><font size="+2"> About the Pan Docs</font></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> =================================================================
|
|||
|
Everything You Always Wanted To Know About GAMEBOY *
|
|||
|
=================================================================
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> * but were afraid to ask
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> Pan of -ATX- Document Updated by contributions from:
|
|||
|
Marat Fayzullin, Pascal Felber, Paul Robson, Martin Korth
|
|||
|
CPU, SGB, CGB, AUX specs by Martin Korth
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> Last updated 10/2001 by nocash
|
|||
|
Previously updated 4-Mar-98 by kOOPa
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>Forward<br>
|
|||
|
</b>The following was typed up for informational purposes regarding the
|
|||
|
inner workings on the hand-held game machine known as GameBoy,
|
|||
|
manufactured and designed by Nintendo Co., LTD. This info is presented
|
|||
|
to inform a user on how their Game Boy works and what makes it "tick".
|
|||
|
GameBoy is copyrighted by Nintendo Co., LTD. Any reference to
|
|||
|
copyrighted material is not presented for monetary gain, but for
|
|||
|
educational purposes and higher learning.<br>
|
|||
|
<br>
|
|||
|
<b>Available Document Formats<br>
|
|||
|
</b>The present version of this document is available in Text and Html format:<br>
|
|||
|
<table><tbody><tr><td><pre> http://www.work.de/nocash/pandocs.txt
|
|||
|
http://www.work.de/nocash/pandocs.htm
|
|||
|
</pre></td></tr></tbody></table>Also, a copy of this document is included in the manual of newer
|
|||
|
versions of the no$gmb debugger, because of recent piracy attacks (many
|
|||
|
thanks and best wishes go to hell) I have currently no intention to
|
|||
|
publish any such or further no$gmb updates though.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="gameboytechnicaldata"></a><font size="+2"> Game Boy Technical Data</font></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> CPU - 8-bit (Similar to the Z80 processor)
|
|||
|
Clock Speed - 4.194304MHz (4.295454MHz for SGB, max. 8.4MHz for CGB)
|
|||
|
Work RAM - 8K Byte (32K Byte for CGB)
|
|||
|
Video RAM - 8K Byte (16K Byte for CGB)
|
|||
|
Screen Size - 2.6"
|
|||
|
Resolution - 160x144 (20x18 tiles)
|
|||
|
Max sprites - Max 40 per screen, 10 per line
|
|||
|
Sprite sizes - 8x8 or 8x16
|
|||
|
Palettes - 1x4 BG, 2x3 OBJ (for CGB: 8x4 BG, 8x3 OBJ)
|
|||
|
Colors - 4 grayshades (32768 colors for CGB)
|
|||
|
Horiz Sync - 9198 KHz (9420 KHz for SGB)
|
|||
|
Vert Sync - 59.73 Hz (61.17 Hz for SGB)
|
|||
|
Sound - 4 channels with stereo sound
|
|||
|
Power - DC6V 0.7W (DC3V 0.7W for GB Pocket, DC3V 0.6W for CGB)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="memorymap"></a><font size="+2"> Memory Map</font></td></tr></tbody></table><br>
|
|||
|
The gameboy is having a 16bit address bus, that is used to address ROM,
|
|||
|
RAM, and I/O registers.<br>
|
|||
|
<br>
|
|||
|
<b>General Memory Map<br>
|
|||
|
</b><table><tbody><tr><td><pre> 0000-3FFF 16KB ROM Bank 00 (in cartridge, fixed at bank 00)
|
|||
|
4000-7FFF 16KB ROM Bank 01..NN (in cartridge, switchable bank number)
|
|||
|
8000-9FFF 8KB Video RAM (VRAM) (switchable bank 0-1 in CGB Mode)
|
|||
|
A000-BFFF 8KB External RAM (in cartridge, switchable bank, if any)
|
|||
|
C000-CFFF 4KB Work RAM Bank 0 (WRAM)
|
|||
|
D000-DFFF 4KB Work RAM Bank 1 (WRAM) (switchable bank 1-7 in CGB Mode)
|
|||
|
E000-FDFF Same as C000-DDFF (ECHO) (typically not used)
|
|||
|
FE00-FE9F Sprite Attribute Table (OAM)
|
|||
|
FEA0-FEFF Not Usable
|
|||
|
FF00-FF7F I/O Ports
|
|||
|
FF80-FFFE High RAM (HRAM)
|
|||
|
FFFF Interrupt Enable Register
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>Jump Vectors in First ROM Bank<br>
|
|||
|
</b>The following addresses are supposed to be used as jump vectors:<br>
|
|||
|
<table><tbody><tr><td><pre> 0000,0008,0010,0018,0020,0028,0030,0038 for RST commands
|
|||
|
0040,0048,0050,0058,0060 for Interrupts
|
|||
|
</pre></td></tr></tbody></table>However, the memory may be used for any other purpose in case that your
|
|||
|
program doesn't use any (or only some) RST commands or Interrupts. RST
|
|||
|
commands are 1-byte opcodes that work similiar to CALL opcodes, except
|
|||
|
that the destination address is fixed.<br>
|
|||
|
<br>
|
|||
|
<b>Cartridge Header in First ROM Bank<br>
|
|||
|
</b>The memory at 0100-014F contains the cartridge header. This area
|
|||
|
contains information about the program, its entry point, checksums,
|
|||
|
information about the used MBC chip, the ROM and RAM sizes, etc. Most of
|
|||
|
the bytes in this area are required to be specified correctly. For more
|
|||
|
information read the chapter about The Cartridge Header.<br>
|
|||
|
<br>
|
|||
|
<b>External Memory and Hardware<br>
|
|||
|
</b>The areas from 0000-7FFF and A000-BFFF may be used to connect external
|
|||
|
hardware. The first area is typically used to address ROM (read only, of
|
|||
|
course), cartridges with Memory Bank Controllers (MBCs) are additionally
|
|||
|
using this area to output data (write only) to the MBC chip. The second
|
|||
|
area is often used to address external RAM, or to address other external
|
|||
|
hardware (Real Time Clock, etc). External memory is often battery
|
|||
|
buffered, and may hold saved game positions and high scrore tables
|
|||
|
(etc.) even when the gameboy is turned of, or when the cartridge is
|
|||
|
removed. For specific information read the chapter about Memory Bank
|
|||
|
Controllers.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="videodisplay"></a><font size="+2"> Video Display</font></td></tr></tbody></table><br>
|
|||
|
<b>Video I/O Registers<br>
|
|||
|
</b><a href="#lcdcontrolregister">LCD Control Register</a><br>
|
|||
|
<a href="#lcdstatusregister">LCD Status Register</a><br>
|
|||
|
<a href="#lcdinterrupts">LCD Interrupts</a><br>
|
|||
|
<a href="#lcdpositionandscrolling">LCD Position and Scrolling</a><br>
|
|||
|
<a href="#lcdmonochromepalettes">LCD Monochrome Palettes</a><br>
|
|||
|
<a href="#lcdcolorpalettescgbonly">LCD Color Palettes (CGB only)</a><br>
|
|||
|
<a href="#lcdvrambankcgbonly">LCD VRAM Bank (CGB only)</a><br>
|
|||
|
<a href="#lcdoamdmatransfers">LCD OAM DMA Transfers</a><br>
|
|||
|
<a href="#lcdvramdmatransferscgbonly">LCD VRAM DMA Transfers (CGB only)</a><br>
|
|||
|
<br>
|
|||
|
<b>Video Memory<br>
|
|||
|
</b><a href="#vramtiledata">VRAM Tile Data</a><br>
|
|||
|
<a href="#vrambackgroundmaps">VRAM Background Maps</a><br>
|
|||
|
<a href="#vramspriteattributetableoam">VRAM Sprite Attribute Table (OAM)</a><br>
|
|||
|
<a href="#accessingvramandoam">Accessing VRAM and OAM</a><br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdcontrolregister"></a><font size="+2"> LCD Control Register</font></td></tr></tbody></table><br>
|
|||
|
<b>FF40 - LCDC - LCD Control (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - LCD Display Enable (0=Off, 1=On)
|
|||
|
Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)
|
|||
|
Bit 5 - Window Display Enable (0=Off, 1=On)
|
|||
|
Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF)
|
|||
|
Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)
|
|||
|
Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16)
|
|||
|
Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)
|
|||
|
Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>LCDC.7 - LCD Display Enable<br>
|
|||
|
</b>CAUTION: Stopping LCD operation (Bit 7 from 1 to 0) may be performed
|
|||
|
during V-Blank ONLY, disabeling the display outside of the V-Blank
|
|||
|
period may damage the hardware. This appears to be a serious issue,
|
|||
|
Nintendo is reported to reject any games that do not follow this rule.<br>
|
|||
|
V-blank can be confirmed when the value of LY is greater than or equal
|
|||
|
to 144. When the display is disabled the screen is blank (white), and
|
|||
|
VRAM and OAM can be accessed freely.<br>
|
|||
|
<br>
|
|||
|
--- LCDC.0 has different Meanings depending on Gameboy Type ---<br>
|
|||
|
<br>
|
|||
|
<b>LCDC.0 - 1) Monochrome Gameboy and SGB: BG Display<br>
|
|||
|
</b>When Bit 0 is cleared, the background becomes blank (white). Window and
|
|||
|
Sprites may still be displayed (if enabled in Bit 1 and/or Bit 5).<br>
|
|||
|
<br>
|
|||
|
<b>LCDC.0 - 2) CGB in CGB Mode: BG and Window Master Priority<br>
|
|||
|
</b>When Bit 0 is cleared, the background and window lose their priority -
|
|||
|
the sprites will be always displayed on top of background and window,
|
|||
|
independently of the priority flags in OAM and BG Map attributes.<br>
|
|||
|
<br>
|
|||
|
<b>LCDC.0 - 3) CGB in Non CGB Mode: BG and Window Display<br>
|
|||
|
</b>When Bit 0 is cleared, both background and window become blank (white),
|
|||
|
ie. the Window Display Bit (Bit 5) is ignored in that case. Only Sprites
|
|||
|
may still be displayed (if enabled in Bit 1).<br>
|
|||
|
This is a possible compatibility problem - any monochrome games (if any)
|
|||
|
that disable the background, but still want to display the window
|
|||
|
wouldn't work properly on CGBs.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdstatusregister"></a><font size="+2"> LCD Status Register</font></td></tr></tbody></table><br>
|
|||
|
<b>FF41 - STAT - LCDC Status (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 6 - LYC=LY Coincidence Interrupt (1=Enable) (Read/Write)
|
|||
|
Bit 5 - Mode 2 OAM Interrupt (1=Enable) (Read/Write)
|
|||
|
Bit 4 - Mode 1 V-Blank Interrupt (1=Enable) (Read/Write)
|
|||
|
Bit 3 - Mode 0 H-Blank Interrupt (1=Enable) (Read/Write)
|
|||
|
Bit 2 - Coincidence Flag (0:LYC<>LY, 1:LYC=LY) (Read Only)
|
|||
|
Bit 1-0 - Mode Flag (Mode 0-3, see below) (Read Only)
|
|||
|
0: During H-Blank
|
|||
|
1: During V-Blank
|
|||
|
2: During Searching OAM-RAM
|
|||
|
3: During Transfering Data to LCD Driver
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
The two lower STAT bits show the current status of the LCD controller.<br>
|
|||
|
<table><tbody><tr><td><pre> Mode 0: The LCD controller is in the H-Blank period and
|
|||
|
the CPU can access both the display RAM (8000h-9FFFh)
|
|||
|
and OAM (FE00h-FE9Fh)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> Mode 1: The LCD contoller is in the V-Blank period (or the
|
|||
|
display is disabled) and the CPU can access both the
|
|||
|
display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> Mode 2: The LCD controller is reading from OAM memory.
|
|||
|
The CPU <cannot> access OAM memory (FE00h-FE9Fh)
|
|||
|
during this period.
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<table><tbody><tr><td><pre> Mode 3: The LCD controller is reading from both OAM and VRAM,
|
|||
|
The CPU <cannot> access OAM and VRAM during this period.
|
|||
|
CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
The following are typical when the display is enabled:<br>
|
|||
|
<table><tbody><tr><td><pre> Mode 2 2_____2_____2_____2_____2_____2___________________2____
|
|||
|
Mode 3 _33____33____33____33____33____33__________________3___
|
|||
|
Mode 0 ___000___000___000___000___000___000________________000
|
|||
|
Mode 1 ____________________________________11111111111111_____
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
The Mode Flag goes through the values 0, 2, and 3 at a cycle of about
|
|||
|
109uS. 0 is present about 48.6uS, 2 about 19uS, and 3 about 41uS. This
|
|||
|
is interrupted every 16.6ms by the VBlank (1). The mode flag stays set
|
|||
|
at 1 for about 1.08 ms.<br>
|
|||
|
<br>
|
|||
|
Mode 0 is present between 201-207 clks, 2 about 77-83 clks, and 3 about
|
|||
|
169-175 clks. A complete cycle through these states takes 456 clks.
|
|||
|
VBlank lasts 4560 clks. A complete screen refresh occurs every 70224
|
|||
|
clks.)<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdinterrupts"></a><font size="+2"> LCD Interrupts</font></td></tr></tbody></table><br>
|
|||
|
<b>INT 40 - V-Blank Interrupt<br>
|
|||
|
</b>The V-Blank interrupt occurs ca. 59.7 times a second on a regular GB and
|
|||
|
ca. 61.1 times a second on a Super GB (SGB). This interrupt occurs at
|
|||
|
the beginning of the V-Blank period (LY=144).<br>
|
|||
|
During this period video hardware is not using video ram so it may be
|
|||
|
freely accessed. This period lasts approximately 1.1 milliseconds.<br>
|
|||
|
<br>
|
|||
|
<b>INT 48 - LCDC Status Interrupt<br>
|
|||
|
</b>There are various reasons for this interrupt to occur as described by
|
|||
|
the STAT register ($FF40). One very popular reason is to indicate to the
|
|||
|
user when the video hardware is about to redraw a given LCD line. This
|
|||
|
can be useful for dynamically controlling the SCX/SCY registers
|
|||
|
($FF43/$FF42) to perform special video effects.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdpositionandscrolling"></a><font size="+2"> LCD Position and Scrolling</font></td></tr></tbody></table><br>
|
|||
|
<b>FF42 - SCY - Scroll Y (R/W)<br>
|
|||
|
FF43 - SCX - Scroll X (R/W)<br>
|
|||
|
</b>Specifies the position in the 256x256 pixels BG map (32x32 tiles) which
|
|||
|
is to be displayed at the upper/left LCD display position.<br>
|
|||
|
Values in range from 0-255 may be used for X/Y each, the video
|
|||
|
controller automatically wraps back to the upper (left) position in BG
|
|||
|
map when drawing exceeds the lower (right) border of the BG map area.<br>
|
|||
|
<br>
|
|||
|
<b>FF44 - LY - LCDC Y-Coordinate (R)<br>
|
|||
|
</b>The LY indicates the vertical line to which the present data is
|
|||
|
transferred to the LCD Driver. The LY can take on any value between 0
|
|||
|
through 153. The values between 144 and 153 indicate the V-Blank period.
|
|||
|
Writing will reset the counter.<br>
|
|||
|
<br>
|
|||
|
<b>FF45 - LYC - LY Compare (R/W)<br>
|
|||
|
</b>The gameboy permanently compares the value of the LYC and LY registers.
|
|||
|
When both values are identical, the coincident bit in the STAT register
|
|||
|
becomes set, and (if enabled) a STAT interrupt is requested.<br>
|
|||
|
<br>
|
|||
|
<b>FF4A - WY - Window Y Position (R/W)<br>
|
|||
|
FF4B - WX - Window X Position minus 7 (R/W)<br>
|
|||
|
</b>Specifies the upper/left positions of the Window area. (The window is an
|
|||
|
alternate background area which can be displayed above of the normal
|
|||
|
background. OBJs (sprites) may be still displayed above or behinf the
|
|||
|
window, just as for normal BG.)<br>
|
|||
|
The window becomes visible (if enabled) when positions are set in range
|
|||
|
WX=0..166, WY=0..143. A postion of WX=7, WY=0 locates the window at
|
|||
|
upper left, it is then completly covering normal background.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdmonochromepalettes"></a><font size="+2"> LCD Monochrome Palettes</font></td></tr></tbody></table><br>
|
|||
|
<b>FF47 - BGP - BG Palette Data (R/W) - Non CGB Mode Only<br>
|
|||
|
</b>This register assigns gray shades to the color numbers of the BG and
|
|||
|
Window tiles.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 7-6 - Shade for Color Number 3
|
|||
|
Bit 5-4 - Shade for Color Number 2
|
|||
|
Bit 3-2 - Shade for Color Number 1
|
|||
|
Bit 1-0 - Shade for Color Number 0
|
|||
|
</pre></td></tr></tbody></table>The four possible gray shades are:<br>
|
|||
|
<table><tbody><tr><td><pre> 0 White
|
|||
|
1 Light gray
|
|||
|
2 Dark gray
|
|||
|
3 Black
|
|||
|
</pre></td></tr></tbody></table>In CGB Mode the Color Palettes are taken from CGB Palette Memory
|
|||
|
instead.<br>
|
|||
|
<br>
|
|||
|
<b>FF48 - OBP0 - Object Palette 0 Data (R/W) - Non CGB Mode Only<br>
|
|||
|
</b>This register assigns gray shades for sprite palette 0. It works exactly
|
|||
|
as BGP (FF47), except that the lower two bits aren't used because sprite
|
|||
|
data 00 is transparent.<br>
|
|||
|
<br>
|
|||
|
<b>FF49 - OBP1 - Object Palette 1 Data (R/W) - Non CGB Mode Only<br>
|
|||
|
</b>This register assigns gray shades for sprite palette 1. It works exactly
|
|||
|
as BGP (FF47), except that the lower two bits aren't used because sprite
|
|||
|
data 00 is transparent.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdcolorpalettescgbonly"></a><font size="+2"> LCD Color Palettes (CGB only)</font></td></tr></tbody></table><br>
|
|||
|
<b>FF68 - BCPS/BGPI - CGB Mode Only - Background Palette Index<br>
|
|||
|
</b>This register is used to address a byte in the CGBs Background Palette
|
|||
|
Memory. Each two byte in that memory define a color value. The first 8
|
|||
|
bytes define Color 0-3 of Palette 0 (BGP0), and so on for BGP1-7.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0-5 Index (00-3F)
|
|||
|
Bit 7 Auto Increment (0=Disabled, 1=Increment after Writing)
|
|||
|
</pre></td></tr></tbody></table>Data can be read/written to/from the specified index address through
|
|||
|
Register FF69. When the Auto Increment Bit is set then the index is
|
|||
|
automatically incremented after each <write> to FF69. Auto Increment has
|
|||
|
no effect when <reading> from FF69, so the index must be manually
|
|||
|
incremented in that case.<br>
|
|||
|
<br>
|
|||
|
<b>FF69 - BCPD/BGPD - CGB Mode Only - Background Palette Data<br>
|
|||
|
</b>This register allows to read/write data to the CGBs Background Palette
|
|||
|
Memory, addressed through Register FF68.<br>
|
|||
|
Each color is defined by two bytes (Bit 0-7 in first byte).<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0-4 Red Intensity (00-1F)
|
|||
|
Bit 5-9 Green Intensity (00-1F)
|
|||
|
Bit 10-14 Blue Intensity (00-1F)
|
|||
|
</pre></td></tr></tbody></table>Much like VRAM, Data in Palette Memory cannot be read/written during the
|
|||
|
time when the LCD Controller is reading from it. (That is when the STAT
|
|||
|
register indicates Mode 3).<br>
|
|||
|
Note: Initially all background colors are initialized as white.<br>
|
|||
|
<br>
|
|||
|
<b>FF6A - OCPS/OBPI - CGB Mode Only - Sprite Palette Index<br>
|
|||
|
FF6B - OCPD/OBPD - CGB Mode Only - Sprite Palette Data<br>
|
|||
|
</b>These registers are used to initialize the Sprite Palettes OBP0-7,
|
|||
|
identically as described above for Background Palettes. Note that four
|
|||
|
colors may be defined for each OBP Palettes - but only Color 1-3 of each
|
|||
|
Sprite Palette can be displayed, Color 0 is always transparent, and can
|
|||
|
be initialized to a don't care value.<br>
|
|||
|
Note: Initially all sprite colors are uninitialized.<br>
|
|||
|
<br>
|
|||
|
<b>RGB Translation by CGBs<br>
|
|||
|
</b>When developing graphics on PCs, note that the RGB values will have
|
|||
|
different appearance on CGB displays as on VGA monitors:<br>
|
|||
|
The highest intensity will produce Light Gray color rather than White.
|
|||
|
The intensities are not linear; the values 10h-1Fh will all appear very
|
|||
|
bright, while medium and darker colors are ranged at 00h-0Fh.<br>
|
|||
|
The CGB display will mix colors quite oddly, increasing intensity of
|
|||
|
only one R,G,B color will also influence the other two R,G,B colors.<br>
|
|||
|
For example, a color setting of 03EFh (Blue=0, Green=1Fh, Red=0Fh) will
|
|||
|
appear as Neon Green on VGA displays, but on the CGB it'll produce a
|
|||
|
decently washed out Yellow.<br>
|
|||
|
<br>
|
|||
|
<b>RGB Translation by GBAs<br>
|
|||
|
</b>Even though GBA is described to be compatible to CGB games, most CGB
|
|||
|
games are completely unplayable on GBAs because most colors are
|
|||
|
invisible (black). Of course, colors such like Black and White will
|
|||
|
appear the same on both CGB and GBA, but medium intensities are arranged
|
|||
|
completely different.<br>
|
|||
|
Intensities in range 00h..0Fh are invisible/black (unless eventually
|
|||
|
under best sunlight circumstances, and when gazing at the screen under
|
|||
|
obscure viewing angles), unfortunately, these intensities are regulary
|
|||
|
used by most existing CGB games for medium and darker colors.<br>
|
|||
|
Newer CGB games may avoid this effect by changing palette data when
|
|||
|
detecting GBA hardware. A relative simple method would be using the
|
|||
|
formula GBA=CGB/2+10h for each R,G,B intensity, probably the result
|
|||
|
won't be perfect, and (once colors became visible) it may turn out that
|
|||
|
the color mixing is different also, anyways, it'd be still ways better
|
|||
|
than no conversion.<br>
|
|||
|
Asides, this translation method should have been VERY easy to implement
|
|||
|
in GBA hardware directly, even though Nintendo obviously failed to do
|
|||
|
so. How did they say, This seal is your assurance for excellence in
|
|||
|
workmanship and so on?<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdvrambankcgbonly"></a><font size="+2"> LCD VRAM Bank (CGB only)</font></td></tr></tbody></table><br>
|
|||
|
<b>FF4F - VBK - CGB Mode Only - VRAM Bank<br>
|
|||
|
</b>This 1bit register selects the current Video Memory (VRAM) Bank.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0 - VRAM Bank (0-1)
|
|||
|
</pre></td></tr></tbody></table>Bank 0 contains 192 Tiles, and two background maps, just as for
|
|||
|
monochrome games. Bank 1 contains another 192 Tiles, and color attribute
|
|||
|
maps for the background maps in bank 0.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdoamdmatransfers"></a><font size="+2"> LCD OAM DMA Transfers</font></td></tr></tbody></table><br>
|
|||
|
<b>FF46 - DMA - DMA Transfer and Start Address (W)<br>
|
|||
|
</b>Writing to this register launches a DMA transfer from ROM or RAM to OAM
|
|||
|
memory (sprite attribute table). The written value specifies the
|
|||
|
transfer source address divided by 100h, ie. source & destination are:<br>
|
|||
|
<table><tbody><tr><td><pre> Source: XX00-XX9F ;XX in range from 00-F1h
|
|||
|
Destination: FE00-FE9F
|
|||
|
</pre></td></tr></tbody></table>It takes 160 microseconds until the transfer has completed (80
|
|||
|
microseconds in CGB Double Speed Mode), during this time the CPU can
|
|||
|
access only HRAM (memory at FF80-FFFE). For this reason, the programmer
|
|||
|
must copy a short procedure into HRAM, and use this procedure to start
|
|||
|
the transfer from inside HRAM, and wait until the transfer has finished:<br>
|
|||
|
<table><tbody><tr><td><pre> ld (0FF46h),a ;start DMA transfer, a=start address/100h
|
|||
|
ld a,28h ;delay...
|
|||
|
wait: ;total 5x40 cycles, approx 200ms
|
|||
|
dec a ;1 cycle
|
|||
|
jr nz,wait ;4 cycles
|
|||
|
</pre></td></tr></tbody></table>Most programs are executing this procedure from inside of their VBlank
|
|||
|
procedure, but it is possible to execute it during display redraw also,
|
|||
|
allowing to display more than 40 sprites on the screen (ie. for example
|
|||
|
40 sprites in upper half, and other 40 sprites in lower half of the
|
|||
|
screen).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="lcdvramdmatransferscgbonly"></a><font size="+2"> LCD VRAM DMA Transfers (CGB only)</font></td></tr></tbody></table><br>
|
|||
|
<b>FF51 - HDMA1 - CGB Mode Only - New DMA Source, High<br>
|
|||
|
FF52 - HDMA2 - CGB Mode Only - New DMA Source, Low<br>
|
|||
|
FF53 - HDMA3 - CGB Mode Only - New DMA Destination, High<br>
|
|||
|
FF54 - HDMA4 - CGB Mode Only - New DMA Destination, Low<br>
|
|||
|
FF55 - HDMA5 - CGB Mode Only - New DMA Length/Mode/Start<br>
|
|||
|
</b>These registers are used to initiate a DMA transfer from ROM or RAM to
|
|||
|
VRAM. The Source Start Address may be located at 0000-7FF0 or A000-DFF0,
|
|||
|
the lower four bits of the address are ignored (treated as zero). The
|
|||
|
Destination Start Address may be located at 8000-9FF0, the lower four
|
|||
|
bits of the address are ignored (treated as zero), the upper 3 bits are
|
|||
|
ignored either (destination is always in VRAM).<br>
|
|||
|
<br>
|
|||
|
Writing to FF55 starts the transfer, the lower 7 bits of FF55 specify
|
|||
|
the Transfer Length (divided by 10h, minus 1). Ie. lengths of 10h-800h
|
|||
|
bytes can be defined by the values 00h-7Fh. And the upper bit of FF55
|
|||
|
indicates the Transfer Mode:<br>
|
|||
|
<br>
|
|||
|
<b>Bit7=0 - General Purpose DMA<br>
|
|||
|
</b>When using this transfer method, all data is transferred at once. The
|
|||
|
execution of the program is halted until the transfer has completed.
|
|||
|
Note that the General Purpose DMA blindly attempts to copy the data,
|
|||
|
even if the LCD controller is currently accessing VRAM. So General
|
|||
|
Purpose DMA should be used only if the Display is disabled, or during
|
|||
|
V-Blank, or (for rather short blocks) during H-Blank.<br>
|
|||
|
The execution of the program continues when the transfer has been
|
|||
|
completed, and FF55 then contains a value if FFh.<br>
|
|||
|
<br>
|
|||
|
<b>Bit7=1 - H-Blank DMA<br>
|
|||
|
</b>The H-Blank DMA transfers 10h bytes of data during each H-Blank, ie. at
|
|||
|
LY=0-143, no data is transferred during V-Blank (LY=144-153), but the
|
|||
|
transfer will then continue at LY=00. The execution of the program is
|
|||
|
halted during the separate transfers, but the program execution
|
|||
|
continues during the 'spaces' between each data block.<br>
|
|||
|
Note that the program may not change the Destination VRAM bank (FF4F),
|
|||
|
or the Source ROM/RAM bank (in case data is transferred from bankable
|
|||
|
memory) until the transfer has completed!<br>
|
|||
|
Reading from Register FF55 returns the remaining length (divided by 10h,
|
|||
|
minus 1), a value of 0FFh indicates that the transfer has completed. It
|
|||
|
is also possible to terminate an active H-Blank transfer by writing zero
|
|||
|
to Bit 7 of FF55. In that case reading from FF55 may return any value
|
|||
|
for the lower 7 bits, but Bit 7 will be read as "1".<br>
|
|||
|
<br>
|
|||
|
<b>Confirming if the DMA Transfer is Active<br>
|
|||
|
</b>Reading Bit 7 of FF55 can be used to confirm if the DMA transfer is
|
|||
|
active (1=Not Active, 0=Active). This works under any circumstances -
|
|||
|
after completion of General Purpose, or H-Blank Transfer, and after
|
|||
|
manually terminating a H-Blank Transfer.<br>
|
|||
|
<br>
|
|||
|
<b>Transfer Timings<br>
|
|||
|
</b>In both Normal Speed and Double Speed Mode it takes about 8us to
|
|||
|
transfer a block of 10h bytes. That are 8 cycles in Normal Speed Mode,
|
|||
|
and 16 'fast' cycles in Double Speed Mode.<br>
|
|||
|
Older MBC controllers (like MBC1-4) and slower ROMs are not guaranteed
|
|||
|
to support General Purpose or H-Blank DMA, that's because there are
|
|||
|
always 2 bytes transferred per microsecond (even if the itself program
|
|||
|
runs it Normal Speed Mode).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="vramtiledata"></a><font size="+2"> VRAM Tile Data</font></td></tr></tbody></table><br>
|
|||
|
Tile Data is stored in VRAM at addresses 8000h-97FFh, this area defines
|
|||
|
the Bitmaps for 192 Tiles. In CGB Mode 384 Tiles can be defined, because
|
|||
|
memory at 0:8000h-97FFh and at 1:8000h-97FFh is used.<br>
|
|||
|
<br>
|
|||
|
Each tile is sized 8x8 pixels and has a color depth of 4 colors/gray
|
|||
|
shades. Tiles can be displayed as part of the Background/Window map,
|
|||
|
and/or as OAM tiles (foreground sprites). Note that foreground sprites
|
|||
|
may have only 3 colors, because color 0 is transparent.<br>
|
|||
|
<br>
|
|||
|
As it was said before, there are two Tile Pattern Tables at $8000-8FFF
|
|||
|
and at $8800-97FF. The first one can be used for sprites and the
|
|||
|
background. Its tiles are numbered from 0 to 255. The second table can
|
|||
|
be used for the background and the window display and its tiles are
|
|||
|
numbered from -128 to 127.<br>
|
|||
|
<br>
|
|||
|
Each Tile occupies 16 bytes, where each 2 bytes represent a line:<br>
|
|||
|
<table><tbody><tr><td><pre> Byte 0-1 First Line (Upper 8 pixels)
|
|||
|
Byte 2-3 Next Line
|
|||
|
etc.
|
|||
|
</pre></td></tr></tbody></table>For each line, the first byte defines the least significant bits of the
|
|||
|
color numbers for each pixel, and the second byte defines the upper bits
|
|||
|
of the color numbers. In either case, Bit 7 is the leftmost pixel, and
|
|||
|
Bit 0 the rightmost.<br>
|
|||
|
<br>
|
|||
|
So, each pixel is having a color number in range from 0-3. The color
|
|||
|
numbers are translated into real colors (or gray shades) depending on
|
|||
|
the current palettes. The palettes are defined through registers
|
|||
|
FF47-FF49 (Non CGB Mode), and FF68-FF6B (CGB Mode).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="vrambackgroundmaps"></a><font size="+2"> VRAM Background Maps</font></td></tr></tbody></table><br>
|
|||
|
The gameboy contains two 32x32 tile background maps in VRAM at addresses
|
|||
|
9800h-9BFFh and 9C00h-9FFFh. Each can be used either to display "normal"
|
|||
|
background, or "window" background.<br>
|
|||
|
<br>
|
|||
|
<b>BG Map Tile Numbers<br>
|
|||
|
</b>An area of VRAM known as Background Tile Map contains the numbers of
|
|||
|
tiles to be displayed. It is organized as 32 rows of 32 bytes each. Each
|
|||
|
byte contains a number of a tile to be displayed. Tile patterns are
|
|||
|
taken from the Tile Data Table located either at $8000-8FFF or
|
|||
|
$8800-97FF. In the first case, patterns are numbered with unsigned
|
|||
|
numbers from 0 to 255 (i.e. pattern #0 lies at address $8000). In the
|
|||
|
second case, patterns have signed numbers from -128 to 127 (i.e. pattern
|
|||
|
#0 lies at address $9000). The Tile Data Table address for the
|
|||
|
background can be selected via LCDC register.<br>
|
|||
|
<br>
|
|||
|
<b>BG Map Attributes (CGB Mode only)<br>
|
|||
|
</b>In CGB Mode, an additional map of 32x32 bytes is stored in VRAM Bank 1
|
|||
|
(each byte defines attributes for the corresponding tile-number map
|
|||
|
entry in VRAM Bank 0):<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0-2 Background Palette number (BGP0-7)
|
|||
|
Bit 3 Tile VRAM Bank number (0=Bank 0, 1=Bank 1)
|
|||
|
Bit 4 Not used
|
|||
|
Bit 5 Horizontal Flip (0=Normal, 1=Mirror horizontally)
|
|||
|
Bit 6 Vertical Flip (0=Normal, 1=Mirror vertically)
|
|||
|
Bit 7 BG-to-OAM Priority (0=Use OAM priority bit, 1=BG Priority)
|
|||
|
</pre></td></tr></tbody></table>When Bit 7 is set, the corresponding BG tile will have priority above
|
|||
|
all OBJs (regardless of the priority bits in OAM memory). There's also
|
|||
|
an Master Priority flag in LCDC register Bit 0 which overrides all other
|
|||
|
priority bits when cleared.<br>
|
|||
|
<br>
|
|||
|
As one background tile has a size of 8x8 pixels, the BG maps may hold a
|
|||
|
picture of 256x256 pixels, an area of 160x144 pixels of this picture can
|
|||
|
be displayed on the LCD screen.<br>
|
|||
|
<br>
|
|||
|
<b>Normal Background (BG)<br>
|
|||
|
</b>The SCY and SCX registers can be used to scroll the background, allowing
|
|||
|
to select the origin of the visible 160x144 pixel area within the total
|
|||
|
256x256 pixel background map. Background wraps around the screen (i.e.
|
|||
|
when part of it goes off the screen, it appears on the opposite side.)<br>
|
|||
|
<br>
|
|||
|
<b>The Window<br>
|
|||
|
</b>Besides background, there is also a "window" overlaying the background.
|
|||
|
The window is not scrollable i.e. it is always displayed starting from
|
|||
|
its left upper corner. The location of a window on the screen can be
|
|||
|
adjusted via WX and WY registers. Screen coordinates of the top left
|
|||
|
corner of a window are WX-7,WY. The tiles for the window are stored in
|
|||
|
the Tile Data Table. Both the Background and the window share the same
|
|||
|
Tile Data Table.<br>
|
|||
|
<br>
|
|||
|
Both background and window can be disabled or enabled separately via
|
|||
|
bits in the LCDC register.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="vramspriteattributetableoam"></a><font size="+2"> VRAM Sprite Attribute Table (OAM)</font></td></tr></tbody></table><br>
|
|||
|
GameBoy video controller can display up to 40 sprites either in 8x8 or
|
|||
|
in 8x16 pixels. Because of a limitation of hardware, only ten sprites
|
|||
|
can be displayed per scan line. Sprite patterns have the same format as
|
|||
|
BG tiles, but they are taken from the Sprite Pattern Table located at
|
|||
|
$8000-8FFF and have unsigned numbering.<br>
|
|||
|
<br>
|
|||
|
Sprite attributes reside in the Sprite Attribute Table (OAM - Object
|
|||
|
Attribute Memory) at $FE00-FE9F. Each of the 40 entries consists of four
|
|||
|
bytes with the following meanings:<br>
|
|||
|
<br>
|
|||
|
<b>Byte0 - Y Position<br>
|
|||
|
</b>Specifies the sprites vertical position on the screen (minus 16).<br>
|
|||
|
An offscreen value (for example, Y=0 or Y>=160) hides the sprite.<br>
|
|||
|
<br>
|
|||
|
<b>Byte1 - X Position<br>
|
|||
|
</b>Specifies the sprites horizontal position on the screen (minus 8).<br>
|
|||
|
An offscreen value (X=0 or X>=168) hides the sprite, but the sprite<br>
|
|||
|
still affects the priority ordering - a better way to hide a sprite is
|
|||
|
to set its Y-coordinate offscreen.<br>
|
|||
|
<br>
|
|||
|
<b>Byte2 - Tile/Pattern Number<br>
|
|||
|
</b>Specifies the sprites Tile Number (00-FF). This (unsigned) value selects
|
|||
|
a tile from memory at 8000h-8FFFh. In CGB Mode this could be either in
|
|||
|
VRAM Bank 0 or 1, depending on Bit 3 of the following byte.<br>
|
|||
|
In 8x16 mode, the lower bit of the tile number is ignored. Ie. the upper
|
|||
|
8x8 tile is "NN AND FEh", and the lower 8x8 tile is "NN OR 01h".<br>
|
|||
|
<br>
|
|||
|
<b>Byte3 - Attributes/Flags:<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit7 OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3)
|
|||
|
(Used for both BG and Window. BG color 0 is always behind OBJ)
|
|||
|
Bit6 Y flip (0=Normal, 1=Vertically mirrored)
|
|||
|
Bit5 X flip (0=Normal, 1=Horizontally mirrored)
|
|||
|
Bit4 Palette number **Non CGB Mode Only** (0=OBP0, 1=OBP1)
|
|||
|
Bit3 Tile VRAM-Bank **CGB Mode Only** (0=Bank 0, 1=Bank 1)
|
|||
|
Bit2-0 Palette number **CGB Mode Only** (OBP0-7)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>Sprite Priorities and Conflicts<br>
|
|||
|
</b>When sprites with different x coordinate values overlap, the one with
|
|||
|
the smaller x coordinate (closer to the left) will have priority and
|
|||
|
appear above any others. This applies in Non CGB Mode only.<br>
|
|||
|
When sprites with the same x coordinate values overlap, they have
|
|||
|
priority according to table ordering. (i.e. $FE00 - highest, $FE04 -
|
|||
|
next highest, etc.) In CGB Mode priorities are always assigned like
|
|||
|
this.<br>
|
|||
|
<br>
|
|||
|
Only 10 sprites can be displayed on any one line. When this limit is
|
|||
|
exceeded, the lower priority sprites (priorities listed above) won't be
|
|||
|
displayed. To keep unused sprites from affecting onscreen sprites set
|
|||
|
their Y coordinate to Y=0 or Y=>144+16. Just setting the X coordinate to
|
|||
|
X=0 or X=>160+8 on a sprite will hide it but it will still affect other
|
|||
|
sprites sharing the same lines.<br>
|
|||
|
<br>
|
|||
|
<b>Writing Data to OAM Memory<br>
|
|||
|
</b>The recommened method is to write the data to normal RAM first, and to
|
|||
|
copy that RAM to OAM by using the DMA transfer function, initiated
|
|||
|
through DMA register (FF46).<br>
|
|||
|
Beside for that, it is also possible to write data directly to the OAM
|
|||
|
area by using normal LD commands, this works only during the H-Blank and
|
|||
|
V-Blank periods. The current state of the LCD controller can be read out
|
|||
|
from the STAT register (FF41).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="accessingvramandoam"></a><font size="+2"> Accessing VRAM and OAM</font></td></tr></tbody></table><br>
|
|||
|
<b>CAUTION<br>
|
|||
|
</b>When the LCD Controller is drawing the screen it is directly reading
|
|||
|
from Video Memory (VRAM) and from the Sprite Attribute Table (OAM).
|
|||
|
During these periods the Gameboy CPU may not access the VRAM and OAM.
|
|||
|
That means, any attempts to write to VRAM/OAM are ignored (the data
|
|||
|
remains unchanged). And any attempts to read from VRAM/OAM will return
|
|||
|
undefined data (typically a value of FFh).<br>
|
|||
|
<br>
|
|||
|
For this reason the program should verify if VRAM/OAM is accessable
|
|||
|
before actually reading or writing to it. This is usually done by
|
|||
|
reading the Mode Bits from the STAT Register (FF41). When doing this (as
|
|||
|
described in the examples below) you should take care that no interrupts
|
|||
|
occur between the wait loops and the following memory access - the
|
|||
|
memory is guaranted to be accessable only for a few cycles directly
|
|||
|
after the wait loops have completed.<br>
|
|||
|
<br>
|
|||
|
<b>VRAM (memory at 8000h-9FFFh) is accessable during Mode 0-2<br>
|
|||
|
</b><table><tbody><tr><td><pre> Mode 0 - H-Blank Period,
|
|||
|
Mode 1 - V-Blank Period, and
|
|||
|
Mode 2 - Searching OAM Period
|
|||
|
</pre></td></tr></tbody></table>A typical procedure that waits for accessibility of VRAM would be:<br>
|
|||
|
<table><tbody><tr><td><pre> ld hl,0FF41h ;-STAT Register
|
|||
|
@@wait: ;\
|
|||
|
bit 1,(hl) ; Wait until Mode is 0 or 1
|
|||
|
jr nz,@@wait ;/
|
|||
|
</pre></td></tr></tbody></table>Even if the procedure gets executed at the <end> of Mode 0 or 1, it is
|
|||
|
still proof to assume that VRAM can be accessed for a few more cycles
|
|||
|
because in either case the following period is Mode 2 which allows
|
|||
|
access to VRAM either.<br>
|
|||
|
In CGB Mode an alternate method to write data to VRAM is to use the HDMA
|
|||
|
Function (FF51-FF55).<br>
|
|||
|
<br>
|
|||
|
<b>OAM (memory at FE00h-FE9Fh) is accessable during Mode 0-1<br>
|
|||
|
</b><table><tbody><tr><td><pre> Mode 0 - H-Blank Period, and
|
|||
|
Mode 1 - V-Blank Period
|
|||
|
</pre></td></tr></tbody></table>Beside for that, OAM can be accessed at any time by using the DMA
|
|||
|
Function (FF46). When directly reading or writing to OAM, a typical
|
|||
|
procedure that waits for accessibilty or OAM Memory would be:<br>
|
|||
|
<table><tbody><tr><td><pre> ld hl,0FF41h ;-STAT Register
|
|||
|
@@wait1: ;\
|
|||
|
bit 1,(hl) ; Wait until Mode is -NOT- 0 or 1
|
|||
|
jr z,@@wait1 ;/
|
|||
|
@@wait2: ;\
|
|||
|
bit 1,(hl) ; Wait until Mode 0 or 1 -BEGINS-
|
|||
|
jr nz,@@wait2 ;/
|
|||
|
</pre></td></tr></tbody></table>The two wait loops ensure that Mode 0 or 1 will last for a few clock
|
|||
|
cycles after completion of the procedure. In V-Blank period it might be
|
|||
|
recommended to skip the whole procedure - and in most cases using the
|
|||
|
above mentioned DMA function would be more recommended anyways.<br>
|
|||
|
<br>
|
|||
|
<b>Note<br>
|
|||
|
</b>When the display is disabled, both VRAM and OAM are accessable at any
|
|||
|
time. The downside is that the screen is blank (white) during this
|
|||
|
period, so that disabling the display would be recommended only during
|
|||
|
initialization.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundcontroller"></a><font size="+2"> Sound Controller</font></td></tr></tbody></table><br>
|
|||
|
<a href="#soundoverview">Sound Overview</a><br>
|
|||
|
<a href="#soundchannel1tonesweep">Sound Channel 1 - Tone & Sweep</a><br>
|
|||
|
<a href="#soundchannel2tone">Sound Channel 2 - Tone</a><br>
|
|||
|
<a href="#soundchannel3waveoutput">Sound Channel 3 - Wave Output</a><br>
|
|||
|
<a href="#soundchannel4noise">Sound Channel 4 - Noise</a><br>
|
|||
|
<a href="#soundcontrolregisters">Sound Control Registers</a><br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundoverview"></a><font size="+2"> Sound Overview</font></td></tr></tbody></table><br>
|
|||
|
There are two sound channels connected to the output terminals SO1 and
|
|||
|
SO2. There is also a input terminal Vin connected to the cartridge. It
|
|||
|
can be routed to either of both output terminals. GameBoy circuitry
|
|||
|
allows producing sound in four different ways:<br>
|
|||
|
<br>
|
|||
|
<table><tbody><tr><td><pre> Quadrangular wave patterns with sweep and envelope functions.
|
|||
|
Quadrangular wave patterns with envelope functions.
|
|||
|
Voluntary wave patterns from wave RAM.
|
|||
|
White noise with an envelope function.
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
These four sounds can be controlled independantly and then mixed
|
|||
|
separately for each of the output terminals.<br>
|
|||
|
<br>
|
|||
|
Sound registers may be set at all times while producing sound.<br>
|
|||
|
<br>
|
|||
|
(Sounds will have a 2.4% higher frequency on Super GB.)<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundchannel1tonesweep"></a><font size="+2"> Sound Channel 1 - Tone & Sweep</font></td></tr></tbody></table><br>
|
|||
|
<b>FF10 - NR10 - Channel 1 Sweep register (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 6-4 - Sweep Time
|
|||
|
Bit 3 - Sweep Increase/Decrease
|
|||
|
0: Addition (frequency increases)
|
|||
|
1: Subtraction (frequency decreases)
|
|||
|
Bit 2-0 - Number of sweep shift (n: 0-7)
|
|||
|
</pre></td></tr></tbody></table>Sweep Time:<br>
|
|||
|
<table><tbody><tr><td><pre> 000: sweep off - no freq change
|
|||
|
001: 7.8 ms (1/128Hz)
|
|||
|
010: 15.6 ms (2/128Hz)
|
|||
|
011: 23.4 ms (3/128Hz)
|
|||
|
100: 31.3 ms (4/128Hz)
|
|||
|
101: 39.1 ms (5/128Hz)
|
|||
|
110: 46.9 ms (6/128Hz)
|
|||
|
111: 54.7 ms (7/128Hz)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
The change of frequency (NR13,NR14) at each shift is calculated by the
|
|||
|
following formula where X(0) is initial freq & X(t-1) is last freq:<br>
|
|||
|
<table><tbody><tr><td><pre> X(t) = X(t-1) +/- X(t-1)/2^n
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>FF11 - NR11 - Channel 1 Sound length/Wave pattern duty (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7-6 - Wave Pattern Duty (Read/Write)
|
|||
|
Bit 5-0 - Sound length data (Write Only) (t1: 0-63)
|
|||
|
</pre></td></tr></tbody></table>Wave Duty:<br>
|
|||
|
<table><tbody><tr><td><pre> 00: 12.5% ( _-------_-------_------- )
|
|||
|
01: 25% ( __------__------__------ )
|
|||
|
10: 50% ( ____----____----____---- ) (normal)
|
|||
|
11: 75% ( ______--______--______-- )
|
|||
|
</pre></td></tr></tbody></table>Sound Length = (64-t1)*(1/256) seconds<br>
|
|||
|
The Length value is used only if Bit 6 in NR14 is set.<br>
|
|||
|
<br>
|
|||
|
<b>FF12 - NR12 - Channel 1 Volume Envelope (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7-4 - Initial Volume of envelope (0-0Fh) (0=No Sound)
|
|||
|
Bit 3 - Envelope Direction (0=Decrease, 1=Increase)
|
|||
|
Bit 2-0 - Number of envelope sweep (n: 0-7)
|
|||
|
(If zero, stop envelope operation.)
|
|||
|
</pre></td></tr></tbody></table>Length of 1 step = n*(1/64) seconds<br>
|
|||
|
<br>
|
|||
|
<b>FF13 - NR13 - Channel 1 Frequency lo (Write Only)<br>
|
|||
|
</b><br>
|
|||
|
Lower 8 bits of 11 bit frequency (x).<br>
|
|||
|
Next 3 bit are in NR14 ($FF14)<br>
|
|||
|
<br>
|
|||
|
<b>FF14 - NR14 - Channel 1 Frequency hi (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Initial (1=Restart Sound) (Write Only)
|
|||
|
Bit 6 - Counter/consecutive selection (Read/Write)
|
|||
|
(1=Stop output when length in NR11 expires)
|
|||
|
Bit 2-0 - Frequency's higher 3 bits (x) (Write Only)
|
|||
|
</pre></td></tr></tbody></table>Frequency = 131072/(2048-x) Hz<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundchannel2tone"></a><font size="+2"> Sound Channel 2 - Tone</font></td></tr></tbody></table><br>
|
|||
|
This sound channel works exactly as channel 1, except that it doesn't
|
|||
|
have a Tone Envelope/Sweep Register.<br>
|
|||
|
<br>
|
|||
|
<b>FF16 - NR21 - Channel 2 Sound Length/Wave Pattern Duty (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7-6 - Wave Pattern Duty (Read/Write)
|
|||
|
Bit 5-0 - Sound length data (Write Only) (t1: 0-63)
|
|||
|
</pre></td></tr></tbody></table>Wave Duty:<br>
|
|||
|
<table><tbody><tr><td><pre> 00: 12.5% ( _-------_-------_------- )
|
|||
|
01: 25% ( __------__------__------ )
|
|||
|
10: 50% ( ____----____----____---- ) (normal)
|
|||
|
11: 75% ( ______--______--______-- )
|
|||
|
</pre></td></tr></tbody></table>Sound Length = (64-t1)*(1/256) seconds<br>
|
|||
|
The Length value is used only if Bit 6 in NR24 is set.<br>
|
|||
|
<br>
|
|||
|
<b>FF17 - NR22 - Channel 2 Volume Envelope (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7-4 - Initial Volume of envelope (0-0Fh) (0=No Sound)
|
|||
|
Bit 3 - Envelope Direction (0=Decrease, 1=Increase)
|
|||
|
Bit 2-0 - Number of envelope sweep (n: 0-7)
|
|||
|
(If zero, stop envelope operation.)
|
|||
|
</pre></td></tr></tbody></table>Length of 1 step = n*(1/64) seconds<br>
|
|||
|
<br>
|
|||
|
<b>FF18 - NR23 - Channel 2 Frequency lo data (W)<br>
|
|||
|
</b>Frequency's lower 8 bits of 11 bit data (x).<br>
|
|||
|
Next 3 bits are in NR24 ($FF19).<br>
|
|||
|
<br>
|
|||
|
<b>FF19 - NR24 - Channel 2 Frequency hi data (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Initial (1=Restart Sound) (Write Only)
|
|||
|
Bit 6 - Counter/consecutive selection (Read/Write)
|
|||
|
(1=Stop output when length in NR21 expires)
|
|||
|
Bit 2-0 - Frequency's higher 3 bits (x) (Write Only)
|
|||
|
</pre></td></tr></tbody></table>Frequency = 131072/(2048-x) Hz<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundchannel3waveoutput"></a><font size="+2"> Sound Channel 3 - Wave Output</font></td></tr></tbody></table><br>
|
|||
|
This channel can be used to output digital sound, the length of the
|
|||
|
sample buffer (Wave RAM) is limited to 32 digits. This sound channel can
|
|||
|
be also used to output normal tones when initializing the Wave RAM by a
|
|||
|
square wave. This channel doesn't have a volume envelope register.<br>
|
|||
|
<br>
|
|||
|
<b>FF1A - NR30 - Channel 3 Sound on/off (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Sound Channel 3 Off (0=Stop, 1=Playback) (Read/Write)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>FF1B - NR31 - Channel 3 Sound Length<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7-0 - Sound length (t1: 0 - 255)
|
|||
|
</pre></td></tr></tbody></table>Sound Length = (256-t1)*(1/256) seconds<br>
|
|||
|
This value is used only if Bit 6 in NR34 is set.<br>
|
|||
|
<br>
|
|||
|
<b>FF1C - NR32 - Channel 3 Select output level (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 6-5 - Select output level (Read/Write)
|
|||
|
</pre></td></tr></tbody></table>Possible Output levels are:<br>
|
|||
|
<table><tbody><tr><td><pre> 0: Mute (No sound)
|
|||
|
1: 100% Volume (Produce Wave Pattern RAM Data as it is)
|
|||
|
2: 50% Volume (Produce Wave Pattern RAM data shifted once to the right)
|
|||
|
3: 25% Volume (Produce Wave Pattern RAM data shifted twice to the right)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>FF1D - NR33 - Channel 3 Frequency's lower data (W)<br>
|
|||
|
</b>Lower 8 bits of an 11 bit frequency (x).<br>
|
|||
|
<br>
|
|||
|
<b>FF1E - NR34 - Channel 3 Frequency's higher data (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Initial (1=Restart Sound) (Write Only)
|
|||
|
Bit 6 - Counter/consecutive selection (Read/Write)
|
|||
|
(1=Stop output when length in NR31 expires)
|
|||
|
Bit 2-0 - Frequency's higher 3 bits (x) (Write Only)
|
|||
|
</pre></td></tr></tbody></table>Frequency = 4194304/(64*(2048-x)) Hz = 65536/(2048-x) Hz<br>
|
|||
|
<br>
|
|||
|
<b>FF30-FF3F - Wave Pattern RAM<br>
|
|||
|
</b>Contents - Waveform storage for arbitrary sound data<br>
|
|||
|
<br>
|
|||
|
This storage area holds 32 4-bit samples that are played back upper 4
|
|||
|
bits first.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundchannel4noise"></a><font size="+2"> Sound Channel 4 - Noise</font></td></tr></tbody></table><br>
|
|||
|
This channel is used to output white noise. This is done by randomly
|
|||
|
switching the amplitude between high and low at a given frequency.
|
|||
|
Depending on the frequency the noise will appear 'harder' or 'softer'.<br>
|
|||
|
<br>
|
|||
|
It is also possible to influence the function of the random generator,
|
|||
|
so the that the output becomes more regular, resulting in a limited
|
|||
|
ability to output Tone instead of Noise.<br>
|
|||
|
<br>
|
|||
|
<b>FF20 - NR41 - Channel 4 Sound Length (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 5-0 - Sound length data (t1: 0-63)
|
|||
|
</pre></td></tr></tbody></table>Sound Length = (64-t1)*(1/256) seconds<br>
|
|||
|
The Length value is used only if Bit 6 in NR44 is set.<br>
|
|||
|
<br>
|
|||
|
<b>FF21 - NR42 - Channel 4 Volume Envelope (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7-4 - Initial Volume of envelope (0-0Fh) (0=No Sound)
|
|||
|
Bit 3 - Envelope Direction (0=Decrease, 1=Increase)
|
|||
|
Bit 2-0 - Number of envelope sweep (n: 0-7)
|
|||
|
(If zero, stop envelope operation.)
|
|||
|
</pre></td></tr></tbody></table>Length of 1 step = n*(1/64) seconds<br>
|
|||
|
<br>
|
|||
|
<b>FF22 - NR43 - Channel 4 Polynomial Counter (R/W)<br>
|
|||
|
</b>The amplitude is randomly switched between high and low at the given
|
|||
|
frequency. A higher frequency will make the noise to appear 'softer'.<br>
|
|||
|
When Bit 3 is set, the output will become more regular, and some
|
|||
|
frequencies will sound more like Tone than Noise.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 7-4 - Shift Clock Frequency (s)
|
|||
|
Bit 3 - Counter Step/Width (0=15 bits, 1=7 bits)
|
|||
|
Bit 2-0 - Dividing Ratio of Frequencies (r)
|
|||
|
</pre></td></tr></tbody></table>Frequency = 524288 Hz / r / 2^(s+1) ;For r=0 assume r=0.5 instead<br>
|
|||
|
<br>
|
|||
|
<b>FF23 - NR44 - Channel 4 Counter/consecutive; Inital (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Initial (1=Restart Sound) (Write Only)
|
|||
|
Bit 6 - Counter/consecutive selection (Read/Write)
|
|||
|
(1=Stop output when length in NR41 expires)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="soundcontrolregisters"></a><font size="+2"> Sound Control Registers</font></td></tr></tbody></table><br>
|
|||
|
<b>FF24 - NR50 - Channel control / ON-OFF / Volume (R/W)<br>
|
|||
|
</b>The volume bits specify the "Master Volume" for Left/Right sound output.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 7 - Output Vin to SO2 terminal (1=Enable)
|
|||
|
Bit 6-4 - SO2 output level (volume) (0-7)
|
|||
|
Bit 3 - Output Vin to SO1 terminal (1=Enable)
|
|||
|
Bit 2-0 - SO1 output level (volume) (0-7)
|
|||
|
</pre></td></tr></tbody></table>The Vin signal is received from the game cartridge bus, allowing
|
|||
|
external hardware in the cartridge to supply a fifth sound channel,
|
|||
|
additionally to the gameboys internal four channels. As far as I know
|
|||
|
this feature isn't used by any existing games.<br>
|
|||
|
<br>
|
|||
|
<b>FF25 - NR51 - Selection of Sound output terminal (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Output sound 4 to SO2 terminal
|
|||
|
Bit 6 - Output sound 3 to SO2 terminal
|
|||
|
Bit 5 - Output sound 2 to SO2 terminal
|
|||
|
Bit 4 - Output sound 1 to SO2 terminal
|
|||
|
Bit 3 - Output sound 4 to SO1 terminal
|
|||
|
Bit 2 - Output sound 3 to SO1 terminal
|
|||
|
Bit 1 - Output sound 2 to SO1 terminal
|
|||
|
Bit 0 - Output sound 1 to SO1 terminal
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>FF26 - NR52 - Sound on/off<br>
|
|||
|
</b>If your GB programs don't use sound then write 00h to this register to
|
|||
|
save 16% or more on GB power consumption. Disabeling the sound
|
|||
|
controller by clearing Bit 7 destroys the contents of all sound
|
|||
|
registers. Also, it is not possible to access any sound registers
|
|||
|
(execpt FF26) while the sound controller is disabled.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 7 - All sound on/off (0: stop all sound circuits) (Read/Write)
|
|||
|
Bit 3 - Sound 4 ON flag (Read Only)
|
|||
|
Bit 2 - Sound 3 ON flag (Read Only)
|
|||
|
Bit 1 - Sound 2 ON flag (Read Only)
|
|||
|
Bit 0 - Sound 1 ON flag (Read Only)
|
|||
|
</pre></td></tr></tbody></table>Bits 0-3 of this register are read only status bits, writing to these
|
|||
|
bits does NOT enable/disable sound. The flags get set when sound output
|
|||
|
is restarted by setting the Initial flag (Bit 7 in NR14-NR44), the flag
|
|||
|
remains set until the sound length has expired (if enabled). A volume
|
|||
|
envelopes which has decreased to zero volume will NOT cause the sound
|
|||
|
flag to go off.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="joypadinput"></a><font size="+2"> Joypad Input</font></td></tr></tbody></table><br>
|
|||
|
<b>FF00 - P1/JOYP - Joypad (R/W)<br>
|
|||
|
</b>The eight gameboy buttons/direction keys are arranged in form of a 2x4
|
|||
|
matrix. Select either button or direction keys by writing to this
|
|||
|
register, then read-out bit 0-3.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 7 - Not used
|
|||
|
Bit 6 - Not used
|
|||
|
Bit 5 - P15 Select Button Keys (0=Select)
|
|||
|
Bit 4 - P14 Select Direction Keys (0=Select)
|
|||
|
Bit 3 - P13 Input Down or Start (0=Pressed) (Read Only)
|
|||
|
Bit 2 - P12 Input Up or Select (0=Pressed) (Read Only)
|
|||
|
Bit 1 - P11 Input Left or Button B (0=Pressed) (Read Only)
|
|||
|
Bit 0 - P10 Input Right or Button A (0=Pressed) (Read Only)
|
|||
|
</pre></td></tr></tbody></table>Note: Most programs are repeatedly reading from this port several times
|
|||
|
(the first reads used as short delay, allowing the inputs to stabilize,
|
|||
|
and only the value from the last read actually used).<br>
|
|||
|
<br>
|
|||
|
<b>Usage in SGB software<br>
|
|||
|
</b>Beside for normal joypad input, SGB games mis-use the joypad register to
|
|||
|
output SGB command packets to the SNES, also, SGB programs may read out
|
|||
|
gamepad states from up to four different joypads which can be connected
|
|||
|
to the SNES.<br>
|
|||
|
See SGB description for details.<br>
|
|||
|
<br>
|
|||
|
<b>INT 60 - Joypad Interrupt<br>
|
|||
|
</b>Joypad interrupt is requested when any of the above Input lines changes
|
|||
|
from High to Low. Generally this should happen when a key becomes
|
|||
|
pressed (provided that the button/direction key is enabled by above
|
|||
|
Bit4/5), however, because of switch bounce, one or more High to Low
|
|||
|
transitions are usually produced both when pressing or releasing a key.<br>
|
|||
|
<br>
|
|||
|
<b>Using the Joypad Interrupt<br>
|
|||
|
</b>It's more or less useless for programmers, even when selecting both
|
|||
|
buttons and direction keys simultaneously it still cannot recognize all
|
|||
|
keystrokes, because in that case a bit might be already held low by a
|
|||
|
button key, and pressing the corresponding direction key would thus
|
|||
|
cause no difference. The only meaningful purpose of the keystroke
|
|||
|
interrupt would be to terminate STOP (low power) standby state.<br>
|
|||
|
Also, the joypad interrupt does not appear to work with CGB and GBA
|
|||
|
hardware (the STOP function can be still terminated by joypad keystrokes
|
|||
|
though).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="serialdatatransferlinkcable"></a><font size="+2"> Serial Data Transfer (Link Cable)</font></td></tr></tbody></table><br>
|
|||
|
<b>FF01 - SB - Serial transfer data (R/W)<br>
|
|||
|
</b>8 Bits of data to be read/written<br>
|
|||
|
<br>
|
|||
|
<b>FF02 - SC - Serial Transfer Control (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7 - Transfer Start Flag (0=No Transfer, 1=Start)
|
|||
|
Bit 1 - Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only **
|
|||
|
Bit 0 - Shift Clock (0=External Clock, 1=Internal Clock)
|
|||
|
</pre></td></tr></tbody></table>The clock signal specifies the rate at which the eight data bits in SB
|
|||
|
(FF01) are transferred. When the gameboy is communicating with another
|
|||
|
gameboy (or other computer) then either one must supply internal clock,
|
|||
|
and the other one must use external clock.<br>
|
|||
|
<br>
|
|||
|
<b>Internal Clock<br>
|
|||
|
</b>In Non-CGB Mode the gameboy supplies an internal clock of 8192Hz only
|
|||
|
(allowing to transfer about 1 KByte per second). In CGB Mode four
|
|||
|
internal clock rates are available, depending on Bit 1 of the SC
|
|||
|
register, and on whether the CGB Double Speed Mode is used:<br>
|
|||
|
<table><tbody><tr><td><pre> 8192Hz - 1KB/s - Bit 1 cleared, Normal
|
|||
|
16384Hz - 2KB/s - Bit 1 cleared, Double Speed Mode
|
|||
|
262144Hz - 32KB/s - Bit 1 set, Normal
|
|||
|
524288Hz - 64KB/s - Bit 1 set, Double Speed Mode
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>External Clock<br>
|
|||
|
</b>The external clock is typically supplied by another gameboy, but might
|
|||
|
be supplied by another computer (for example if connected to a PCs
|
|||
|
parallel port), in that case the external clock may have any speed. Even
|
|||
|
the old/monochrome gameboy is reported to recognizes external clocks of
|
|||
|
up to 500KHz. And there is no limitiation into the other direction -
|
|||
|
even when suppling an external clock speed of "1 bit per month", then
|
|||
|
the gameboy will still eagerly wait for the next bit(s) to be
|
|||
|
transferred. It isn't required that the clock pulses are sent at an
|
|||
|
regular interval either.<br>
|
|||
|
<br>
|
|||
|
<b>Timeouts<br>
|
|||
|
</b>When using external clock then the transfer will not complete until the
|
|||
|
last bit is received. In case that the second gameboy isn't supplying a
|
|||
|
clock signal, if it gets turned off, or if there is no second gameboy
|
|||
|
connected at all) then transfer will never complete. For this reason the
|
|||
|
transfer procedure should use a timeout counter, and abort the
|
|||
|
communication if no response has been received during the timeout
|
|||
|
interval.<br>
|
|||
|
<br>
|
|||
|
<b>Delays and Synchronization<br>
|
|||
|
</b>The gameboy that is using internal clock should always execute a small
|
|||
|
delay between each transfer, in order to ensure that the opponent
|
|||
|
gameboy has enough time to prepare itself for the next transfer, ie. the
|
|||
|
gameboy with external clock must have set its transfer start bit before
|
|||
|
the gameboy with internal clock starts the transfer. Alternately, the
|
|||
|
two gameboys could switch between internal and external clock for each
|
|||
|
transferred byte to ensure synchronization.<br>
|
|||
|
<br>
|
|||
|
Transfer is initiated by setting the Transfer Start Flag. This bit is
|
|||
|
automatically set to 0 at the end of Transfer. Reading this bit can be
|
|||
|
used to determine if the transfer is still active.<br>
|
|||
|
<br>
|
|||
|
<b>INT 58 - Serial Interrupt<br>
|
|||
|
</b>When the transfer has completed (ie. after sending/receiving 8 bits, if
|
|||
|
any) then an interrupt is requested by setting Bit 3 of the IF Register
|
|||
|
(FF0F). When that interrupt is enabled, then the Serial Interrupt vector
|
|||
|
at 0058 is called.<br>
|
|||
|
<br>
|
|||
|
<b>XXXXXX...<br>
|
|||
|
</b><br>
|
|||
|
Transmitting and receiving serial data is done simultaneously. The
|
|||
|
received data is automatically stored in SB.<br>
|
|||
|
<br>
|
|||
|
The serial I/O port on the Gameboy is a very simple setup and is crude
|
|||
|
compared to standard RS-232 (IBM-PC) or RS-485 (Macintosh) serial ports.
|
|||
|
There are no start or stop bits.<br>
|
|||
|
<br>
|
|||
|
During a transfer, a byte is shifted in at the same time that a byte is
|
|||
|
shifted out. The rate of the shift is determined by whether the clock
|
|||
|
source is internal or external.<br>
|
|||
|
The most significant bit is shifted in and out first.<br>
|
|||
|
<br>
|
|||
|
When the internal clock is selected, it drives the clock pin on the game
|
|||
|
link port and it stays high when not used. During a transfer it will go
|
|||
|
low eight times to clock in/out each bit.<br>
|
|||
|
<br>
|
|||
|
The state of the last bit shifted out determines the state of the output
|
|||
|
line until another transfer takes place.<br>
|
|||
|
<br>
|
|||
|
If a serial transfer with internal clock is performed and no external
|
|||
|
GameBoy is present, a value of $FF will be received in the transfer.<br>
|
|||
|
<br>
|
|||
|
The following code causes $75 to be shifted out the serial port and a
|
|||
|
byte to be shifted into $FF01:<br>
|
|||
|
<br>
|
|||
|
<table><tbody><tr><td><pre> ld a,$75
|
|||
|
ld ($FF01),a
|
|||
|
ld a,$81
|
|||
|
ld ($FF02),a
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="timeranddividerregisters"></a><font size="+2"> Timer and Divider Registers</font></td></tr></tbody></table><br>
|
|||
|
<b>FF04 - DIV - Divider Register (R/W)<br>
|
|||
|
</b>This register is incremented at rate of 16384Hz (~16779Hz on SGB). In
|
|||
|
CGB Double Speed Mode it is incremented twice as fast, ie. at 32768Hz.
|
|||
|
Writing any value to this register resets it to 00h.<br>
|
|||
|
<br>
|
|||
|
<b>FF05 - TIMA - Timer counter (R/W)<br>
|
|||
|
</b>This timer is incremented by a clock frequency specified by the TAC
|
|||
|
register ($FF07). When the value overflows (gets bigger than FFh) then
|
|||
|
it will be reset to the value specified in TMA (FF06), and an interrupt
|
|||
|
will be requested, as described below.<br>
|
|||
|
<br>
|
|||
|
<b>FF06 - TMA - Timer Modulo (R/W)<br>
|
|||
|
</b>When the TIMA overflows, this data will be loaded.<br>
|
|||
|
<br>
|
|||
|
<b>FF07 - TAC - Timer Control (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 2 - Timer Stop (0=Stop, 1=Start)
|
|||
|
Bits 1-0 - Input Clock Select
|
|||
|
00: 4096 Hz (~4194 Hz SGB)
|
|||
|
01: 262144 Hz (~268400 Hz SGB)
|
|||
|
10: 65536 Hz (~67110 Hz SGB)
|
|||
|
11: 16384 Hz (~16780 Hz SGB)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>INT 50 - Timer Interrupt<br>
|
|||
|
</b>Each time when the timer overflows (ie. when TIMA gets bigger than FFh),
|
|||
|
then an interrupt is requested by setting Bit 2 in the IF Register
|
|||
|
(FF0F). When that interrupt is enabled, then the CPU will execute it by
|
|||
|
calling the timer interrupt vector at 0050h.<br>
|
|||
|
<br>
|
|||
|
<b>Note<br>
|
|||
|
</b>The above described Timer is the built-in timer in the gameboy. It has
|
|||
|
nothing to do with the MBC3s battery buffered Real Time Clock - that's a
|
|||
|
completely different thing, described in the chapter about Memory
|
|||
|
Banking Controllers.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="interrupts"></a><font size="+2"> Interrupts</font></td></tr></tbody></table><br>
|
|||
|
<b>IME - Interrupt Master Enable Flag (Write Only)<br>
|
|||
|
</b><table><tbody><tr><td><pre> 0 - Disable all Interrupts
|
|||
|
1 - Enable all Interrupts that are enabled in IE Register (FFFF)
|
|||
|
</pre></td></tr></tbody></table>The IME flag is used to disable all interrupts, overriding any enabled
|
|||
|
bits in the IE Register. It isn't possible to access the IME flag by
|
|||
|
using a I/O address, instead IME is accessed directly from the CPU, by
|
|||
|
the following opcodes/operations:<br>
|
|||
|
<table><tbody><tr><td><pre> EI ;Enable Interrupts (ie. IME=1)
|
|||
|
DI ;Disable Interrupts (ie. IME=0)
|
|||
|
RETI ;Enable Ints & Return (same as the opcode combination EI, RET)
|
|||
|
<INT> ;Disable Ints & Call to Interrupt Vector
|
|||
|
</pre></td></tr></tbody></table>Whereas <INT> means the operation which is automatically executed by the
|
|||
|
CPU when it executes an interrupt.<br>
|
|||
|
<br>
|
|||
|
<b>FFFF - IE - Interrupt Enable (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 0: V-Blank Interrupt Enable (INT 40h) (1=Enable)
|
|||
|
Bit 1: LCD STAT Interrupt Enable (INT 48h) (1=Enable)
|
|||
|
Bit 2: Timer Interrupt Enable (INT 50h) (1=Enable)
|
|||
|
Bit 3: Serial Interrupt Enable (INT 58h) (1=Enable)
|
|||
|
Bit 4: Joypad Interrupt Enable (INT 60h) (1=Enable)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>FF0F - IF - Interrupt Flag (R/W)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 0: V-Blank Interrupt Request (INT 40h) (1=Request)
|
|||
|
Bit 1: LCD STAT Interrupt Request (INT 48h) (1=Request)
|
|||
|
Bit 2: Timer Interrupt Request (INT 50h) (1=Request)
|
|||
|
Bit 3: Serial Interrupt Request (INT 58h) (1=Request)
|
|||
|
Bit 4: Joypad Interrupt Request (INT 60h) (1=Request)
|
|||
|
</pre></td></tr></tbody></table>When an interrupt signal changes from low to high, then the
|
|||
|
corresponding bit in the IF register becomes set. For example, Bit 0
|
|||
|
becomes set when the LCD controller enters into the V-Blank period.<br>
|
|||
|
<br>
|
|||
|
<b>Interrupt Requests<br>
|
|||
|
</b>Any set bits in the IF register are only <requesting> an interrupt to be
|
|||
|
executed. The actual <execution> happens only if both the IME flag, and
|
|||
|
the corresponding bit in the IE register are set, otherwise the
|
|||
|
interrupt 'waits' until both IME and IE allow its execution.<br>
|
|||
|
<br>
|
|||
|
<b>Interrupt Execution<br>
|
|||
|
</b>When an interrupt gets executed, the corresponding bit in the IF
|
|||
|
register becomes automatically reset by the CPU, and the IME flag
|
|||
|
becomes cleared (disabeling any further interrupts until the program
|
|||
|
re-enables the interrupts, typically by using the RETI instruction), and
|
|||
|
the corresponding Interrupt Vector (that are the addresses in range
|
|||
|
0040h-0060h, as shown in IE and IF register decriptions above) becomes
|
|||
|
called.<br>
|
|||
|
<br>
|
|||
|
<b>Manually Requesting/Discarding Interrupts<br>
|
|||
|
</b>As the CPU automatically sets and cleares the bits in the IF register it
|
|||
|
is usually not required to write to the IF register. However, the user
|
|||
|
may still do that in order to manually request (or discard) interrupts.
|
|||
|
As for real interrupts, a manually requested interrupt isn't executed
|
|||
|
unless/until IME and IE allow its execution.<br>
|
|||
|
<br>
|
|||
|
<b>Interrupt Priorities<br>
|
|||
|
</b>In the following three situations it might happen that more than 1 bit
|
|||
|
in the IF register are set, requesting more than one interrupt at once:<br>
|
|||
|
<table><tbody><tr><td><pre> 1) More than one interrupt signal changed from Low
|
|||
|
to High at the same time.
|
|||
|
2) Several interrupts have been requested during a
|
|||
|
time in which IME/IE didn't allow these interrupts
|
|||
|
to be executed directly.
|
|||
|
3) The user has written a value with several "1" bits
|
|||
|
(for example 1Fh) to the IF register.
|
|||
|
</pre></td></tr></tbody></table>Provided that IME and IE allow the execution of more than one of the
|
|||
|
requested interrupts, then the interrupt with the highest priority
|
|||
|
becomes executed first. The priorities are ordered as the bits in the IE
|
|||
|
and IF registers, Bit 0 (V-Blank) having the highest priority, and Bit 4
|
|||
|
(Joypad) having the lowest priority.<br>
|
|||
|
<br>
|
|||
|
<b>Nested Interrupts<br>
|
|||
|
</b>The CPU automatically disables all other interrupts by setting IME=0
|
|||
|
when it executes an interrupt. Usually IME remains zero until the
|
|||
|
interrupt procedure returns (and sets IME=1 by the RETI instruction).
|
|||
|
However, if you want any other interrupts of lower or higher (or same)
|
|||
|
priority to be allowed to be executed from inside of the interrupt
|
|||
|
procedure, then you can place an EI instruction into the interrupt
|
|||
|
procedure.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="cgbregisters"></a><font size="+2"> CGB Registers</font></td></tr></tbody></table><br>
|
|||
|
<b>Forward<br>
|
|||
|
</b>This chapter describes only CGB (Color Gameboy) registers that didn't
|
|||
|
fit into normal categories - most CGB registers are described in the
|
|||
|
chapter about Video Display (Color Palettes, VRAM Bank, VRAM DMA
|
|||
|
Transfers, and changed meaning of Bit 0 of LCDC Control register). Also,
|
|||
|
a changed bit is noted in the chapter about the Serial/Link port.<br>
|
|||
|
<br>
|
|||
|
<b>Unlocking CGB functions<br>
|
|||
|
</b>When using any CGB registers (including those in the Video/Link
|
|||
|
chapters), you must first unlock CGB features by changing byte 0143h in
|
|||
|
the cartridge header. Typically use a value of 80h for games which
|
|||
|
support both CGB and monochrome gameboys, and C0h for games which work
|
|||
|
on CGBs only. Otherwise, the CGB will operate in monochrome "Non CGB"
|
|||
|
compatibility mode.<br>
|
|||
|
<br>
|
|||
|
<b>Detecting CGB (and GBA) functions<br>
|
|||
|
</b>CGB hardware can be detected by examing the CPU accumulator (A-register)
|
|||
|
directly after startup. A value of 11h indicates CGB (or GBA) hardware,
|
|||
|
if so, CGB functions can be used (if unlocked, see above).<br>
|
|||
|
When A=11h, you may also examine Bit 0 of the CPUs B-Register to
|
|||
|
separate between CGB (bit cleared) and GBA (bit set), by that detection
|
|||
|
it is possible to use 'repaired' color palette data matching for GBA
|
|||
|
displays.<br>
|
|||
|
<br>
|
|||
|
<b>FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit 7: Current Speed (0=Normal, 1=Double) (Read Only)
|
|||
|
Bit 0: Prepare Speed Switch (0=No, 1=Prepare) (Read/Write)
|
|||
|
</pre></td></tr></tbody></table>This register is used to prepare the gameboy to switch between CGB
|
|||
|
Double Speed Mode and Normal Speed Mode. The actual speed switch is
|
|||
|
performed by executing a STOP command after Bit 0 has been set. After
|
|||
|
that Bit 0 will be cleared automatically, and the gameboy will operate
|
|||
|
at the 'other' speed. The recommended speed switching procedure in
|
|||
|
pseudo code would be:<br>
|
|||
|
<table><tbody><tr><td><pre> IF KEY1_BIT7 <> DESIRED_SPEED THEN
|
|||
|
IE=00H ;(FFFF)=00h
|
|||
|
JOYP=30H ;(FF00)=30h
|
|||
|
KEY1=01H ;(FF4D)=01h
|
|||
|
STOP ;STOP
|
|||
|
ENDIF
|
|||
|
</pre></td></tr></tbody></table>The CGB is operating in Normal Speed Mode when it is turned on. Note
|
|||
|
that using the Double Speed Mode increases the power consumption, it
|
|||
|
would be recommended to use Single Speed whenever possible. However, the
|
|||
|
display will flicker (white) for a moment during speed switches, so this
|
|||
|
cannot be done permanentely.<br>
|
|||
|
In Double Speed Mode the following will operate twice as fast as normal:<br>
|
|||
|
<table><tbody><tr><td><pre> The CPU (2.10 MHz, 1 Cycle = approx. 0.5us)
|
|||
|
Timer and Divider Registers
|
|||
|
Serial Port (Link Cable)
|
|||
|
DMA Transfer to OAM
|
|||
|
</pre></td></tr></tbody></table>And the following will keep operating as usual:<br>
|
|||
|
<table><tbody><tr><td><pre> LCD Video Controller
|
|||
|
HDMA Transfer to VRAM
|
|||
|
All Sound Timings and Frequencies
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>FF56 - RP - CGB Mode Only - Infrared Communications Port<br>
|
|||
|
</b>This register allows to input and output data through the CGBs built-in
|
|||
|
Infrared Port. When reading data, bit 6 and 7 must be set (and obviously
|
|||
|
Bit 0 must be cleared - if you don't want to receive your own gameboys
|
|||
|
IR signal). After sending or receiving data you should reset the
|
|||
|
register to 00h to reduce battery power consumption again.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0: Write Data (0=LED Off, 1=LED On) (Read/Write)
|
|||
|
Bit 1: Read Data (0=Receiving IR Signal, 1=Normal) (Read Only)
|
|||
|
Bit 6-7: Data Read Enable (0=Disable, 3=Enable) (Read/Write)
|
|||
|
</pre></td></tr></tbody></table>Note that the receiver will adapt itself to the normal level of IR
|
|||
|
pollution in the air, so if you would send a LED ON signal for a longer
|
|||
|
period, then the receiver would treat that as normal (=OFF) after a
|
|||
|
while. For example, a Philips TV Remote Control sends a series of 32 LED
|
|||
|
ON/OFF pulses (length 10us ON, 17.5us OFF each) instead of a permanent
|
|||
|
880us LED ON signal.<br>
|
|||
|
Even though being generally CGB compatible, the GBA does not include an
|
|||
|
infra-red port.<br>
|
|||
|
<br>
|
|||
|
<b>FF70 - SVBK - CGB Mode Only - WRAM Bank<br>
|
|||
|
</b>In CGB Mode 32 KBytes internal RAM are available. This memory is divided
|
|||
|
into 8 banks of 4 KBytes each. Bank 0 is always available in memory at
|
|||
|
C000-CFFF, Bank 1-7 can be selected into the address space at D000-DFFF.<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0-2 Select WRAM Bank (Read/Write)
|
|||
|
</pre></td></tr></tbody></table>Writing a value of 01h-07h will select Bank 1-7, writing a value of 00h
|
|||
|
will select Bank 1 either.<br>
|
|||
|
<br>
|
|||
|
<b>FF6C - Undocumented (FEh) - Bit 0 (Read/Write) - CGB Mode Only<br>
|
|||
|
FF72 - Undocumented (00h) - Bit 0-7 (Read/Write)<br>
|
|||
|
FF73 - Undocumented (00h) - Bit 0-7 (Read/Write)<br>
|
|||
|
FF74 - Undocumented (00h) - Bit 0-7 (Read/Write) - CGB Mode Only<br>
|
|||
|
FF75 - Undocumented (8Fh) - Bit 4-6 (Read/Write)<br>
|
|||
|
FF76 - Undocumented (00h) - Always 00h (Read Only)<br>
|
|||
|
FF77 - Undocumented (00h) - Always 00h (Read Only)<br>
|
|||
|
</b>These are undocumented CGB Registers. The numbers in brackets ()
|
|||
|
indicate the initial values. Purpose of these registers is unknown (if
|
|||
|
any). Registers FF6C and FF74 are always FFh if the CGB is in Non CGB
|
|||
|
Mode.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbfunctions"></a><font size="+2"> SGB Functions</font></td></tr></tbody></table><br>
|
|||
|
<b>General Information<br>
|
|||
|
</b><a href="#sgbdescription">SGB Description</a><br>
|
|||
|
<a href="#sgbunlockinganddetectingsgbfunctions">SGB Unlocking and Detecting SGB Functions</a><br>
|
|||
|
<a href="#sgbcommandpackettransfers">SGB Command Packet Transfers</a><br>
|
|||
|
<a href="#sgbvramtransfers">SGB VRAM Transfers</a><br>
|
|||
|
<a href="#sgbcommandsummary">SGB Command Summary</a><br>
|
|||
|
<a href="#sgbcolorpalettesoverview">SGB Color Palettes Overview</a><br>
|
|||
|
<br>
|
|||
|
<b>SGB Commands<br>
|
|||
|
</b><a href="#sgbpalettecommands">SGB Palette Commands</a><br>
|
|||
|
<a href="#sgbcolorattributecommands">SGB Color Attribute Commands</a><br>
|
|||
|
<a href="#sgbsoundfunctions">SGB Sound Functions</a><br>
|
|||
|
<a href="#sgbsystemcontrolcommands">SGB System Control Commands</a><br>
|
|||
|
<a href="#sgbmultiplayercommand">SGB Multiplayer Command</a><br>
|
|||
|
<a href="#sgbborderandobjcommands">SGB Border and OBJ Commands</a><br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbdescription"></a><font size="+2"> SGB Description</font></td></tr></tbody></table><br>
|
|||
|
<b>General Description<br>
|
|||
|
</b>Basically, the SGB (Super Gameboy) is an adapter cartridge that allows
|
|||
|
to play gameboy games on a SNES (Super Nintendo Entertainment System)
|
|||
|
gaming console. In detail, you plug the gameboy cartridge into the SGB
|
|||
|
cartridge, then plug the SGB cartridge into the SNES, and then connect
|
|||
|
the SNES to your TV Set. In result, games can be played and viewed on
|
|||
|
the TV Set, and are controlled by using the SNES joypad(s).<br>
|
|||
|
<br>
|
|||
|
<b>More Technical Description<br>
|
|||
|
</b>The SGB cartridge just contains a normal gameboy CPU and normal gameboy
|
|||
|
video controller. Normally the video signal from this controller would
|
|||
|
be sent to the LCD screen, however, in this special case the SNES read
|
|||
|
out the video signal and displays it on the TV set by using a special
|
|||
|
SNES BIOS ROM which is located in the SGB cartridge. Also, normal
|
|||
|
gameboy sound output is forwared to the SNES and output to the TV Set,
|
|||
|
vice versa, joypad input is forwared from the SNES controller(s) to the
|
|||
|
gameboy joypad inputs.<br>
|
|||
|
<br>
|
|||
|
<b>Normal Monochrome Games<br>
|
|||
|
</b>Any gameboy games which have been designed for normal monochrome
|
|||
|
handheld gameboys will work with the SGB hardware as well. The SGB will
|
|||
|
apply a four color palette to these games by replacing the normal four
|
|||
|
grayshades. The 160x144 pixel gamescreen is displayed in the middle of
|
|||
|
the 256x224 pixel SNES screen (the unused area is filled by a screen
|
|||
|
border bitmap). The user may access built-in menues, allowing to change
|
|||
|
color palette data, to select between several pre-defined borders, etc.<br>
|
|||
|
<br>
|
|||
|
Games that have been designed to support SGB functions may also access
|
|||
|
the following additional features:<br>
|
|||
|
<br>
|
|||
|
<b>Colorized Game Screen<br>
|
|||
|
</b>There's limited ability to colorize the gamescreen by assigning custom
|
|||
|
color palettes to each 20x18 display characters, however, this works
|
|||
|
mainly for static display data such like title screens or status bars,
|
|||
|
the 20x18 color attribute map is non-scrollable, and it is not possible
|
|||
|
to assign separate colors to moveable foreground sprites (OBJs), so that
|
|||
|
animated screen regions will be typically restricted to using a single
|
|||
|
palette of four colors only.<br>
|
|||
|
<br>
|
|||
|
<b>SNES Foreground Sprites<br>
|
|||
|
</b>Up to 24 foreground sprites (OBJs) of 8x8 or 16x16 pixels, 16 colors can
|
|||
|
be displayed. When replacing (or just overlaying) the normal gameboy
|
|||
|
OBJs by SNES OBJs it'd be thus possible to display OBJs with other
|
|||
|
colors than normal background area. This method doesn't appear to be
|
|||
|
very popular, even though it appears to be quite easy to implement,
|
|||
|
however, the bottommost character line of the gamescreen will be masked
|
|||
|
out because this area is used to transfer OAM data to the SNES.<br>
|
|||
|
<br>
|
|||
|
<b>The SGB Border<br>
|
|||
|
</b>The possibly most popular and most impressive feature is to replace the
|
|||
|
default SGB screen border by a custom bitmap which is stored in the game
|
|||
|
cartridge.<br>
|
|||
|
<br>
|
|||
|
<b>Multiple Joypads<br>
|
|||
|
</b>Up to four joypads can be conected to the SNES, and SGB software may
|
|||
|
read-out each of these joypads separately, allowing up to four players
|
|||
|
to play the same game simultaneously. Unlike for multiplayer handheld
|
|||
|
games, this requires only one game cartridge and only one SGB/SNES, and
|
|||
|
no link cables are required, the downside is that all players must share
|
|||
|
the same display screen.<br>
|
|||
|
<br>
|
|||
|
<b>Sound Functions<br>
|
|||
|
</b>Beside for normal gameboy sound, a number of digital sound effects is
|
|||
|
pre-defined in the SNES BIOS, these effects may be accessed quite
|
|||
|
easily. Programmers whom are familiar with SNES sounds may also access
|
|||
|
the SNES sound chip, or use the SNES MIDI engine directly in order to
|
|||
|
produce other sound effects or music.<br>
|
|||
|
<br>
|
|||
|
<b>Taking Control of the SNES CPU<br>
|
|||
|
</b>Finally, it is possible to write program code or data into SNES memory,
|
|||
|
and to execute such program code by using the SNES CPU.<br>
|
|||
|
<br>
|
|||
|
<b>SGB System Clock<br>
|
|||
|
</b>Because the SGB is synchronized to the SNES CPU, the gameboy system
|
|||
|
clock is directly chained to the SNES system clock. In result, the
|
|||
|
gameboy CPU, video controller, timers, and sound frequencies will be all
|
|||
|
operated approx 2.4% faster as by normal gameboys.<br>
|
|||
|
Basically, this should be no problem, and the game will just run a
|
|||
|
little bit faster. However sensitive musicians may notice that sound
|
|||
|
frequencies are a bit too high, programs that support SGB functions may
|
|||
|
avoid this effect by reducing frequencies of gameboy sounds when having
|
|||
|
detected SGB hardware.<br>
|
|||
|
Also, I think that I've heard that SNES models which use a 50Hz display
|
|||
|
refresh rate (rather than 60Hz) are resulting in respectively slower
|
|||
|
SGB/gameboy timings ???<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbunlockinganddetectingsgbfunctions"></a><font size="+2"> SGB Unlocking and Detecting SGB Functions</font></td></tr></tbody></table><br>
|
|||
|
<b>Cartridge Header<br>
|
|||
|
</b>SGB games are required to have a cartridge header with Nintendo and
|
|||
|
proper checksum just as normal gameboy games. Also, two special entries
|
|||
|
must be set in order to unlock SGB functions:<br>
|
|||
|
<table><tbody><tr><td><pre> 146h - SGB Flag - Must be set to 03h for SGB games
|
|||
|
14Bh - Old Licensee Code - Must be set 33h for SGB games
|
|||
|
</pre></td></tr></tbody></table>When these entries aren't set, the game will still work just like all
|
|||
|
'monochrome' gameboy games, but it cannot access any of the special SGB
|
|||
|
functions.<br>
|
|||
|
<br>
|
|||
|
<b>Detecting SGB hardware<br>
|
|||
|
</b>The recommended detection method is to send a MLT_REQ command which
|
|||
|
enables two (or four) joypads. A normal handheld gameboy will ignore
|
|||
|
this command, a SGB will now return incrementing joypad IDs each time
|
|||
|
when deselecting keyboard lines (see MLT_REQ description for details).<br>
|
|||
|
Now read-out joypad state/IDs several times, and if the ID-numbers are
|
|||
|
changing, then it is a SGB (a normal gameboy would typically always
|
|||
|
return 0Fh as ID). Finally, when not intending to use more than one
|
|||
|
joypad, send another MLT_REQ command in order to re-disable the
|
|||
|
multi-controller mode.<br>
|
|||
|
Detection works regardless of whether and how many joypads are
|
|||
|
physically connected to the SNES. However, detection works only when
|
|||
|
having unlocked SGB functions in the cartridge header, as described
|
|||
|
above. <br>
|
|||
|
<br>
|
|||
|
<b>Separating between SGB and SGB2<br>
|
|||
|
</b>It is also possible to separate between SGB and SGB2 models by examining
|
|||
|
the inital value of the accumulator (A-register) directly after startup.<br>
|
|||
|
<table><tbody><tr><td><pre> 01h SGB or Normal Gameboy (DMG)
|
|||
|
FFh SGB2 or Pocket Gameboy
|
|||
|
11h CGB or GBA
|
|||
|
</pre></td></tr></tbody></table>Because values 01h and FFh are shared for both handhelds and SGBs, it is
|
|||
|
still required to use the above MLT_REQ detection procedure. As far as I
|
|||
|
know the SGB2 doesn't have any extra features which'd require separate
|
|||
|
SGB2 detection except for curiosity purposes, for example, the game
|
|||
|
"Tetris DX" chooses to display an alternate SGB border on SGB2s.<br>
|
|||
|
<br>
|
|||
|
Reportedly, some SGB models include link ports (just like handheld
|
|||
|
gameboy) (my own SGB does not have such an port), possibly this feature
|
|||
|
is available in SGB2-type models only ???<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbcommandpackettransfers"></a><font size="+2"> SGB Command Packet Transfers</font></td></tr></tbody></table><br>
|
|||
|
Command packets (aka Register Files) are transferred from the gameboy to
|
|||
|
the SNES by using P14 and P15 output lines of the JOYPAD register
|
|||
|
(FF00h), these lines are normally used to select the two rows in the
|
|||
|
gameboy keyboard matrix (which still works).<br>
|
|||
|
<br>
|
|||
|
<b>Transferring Bits<br>
|
|||
|
</b>A command packet transfer must be initiated by setting both P14 and P15
|
|||
|
to LOW, this will reset and start the SNES packet receiving program.
|
|||
|
Data is then transferred (LSB first), setting P14=LOW will indicate a
|
|||
|
"0" bit, and setting P15=LOW will indicate a "1" bit. For example:<br>
|
|||
|
<table><tbody><tr><td><pre> RESET 0 0 1 1 0 1 0
|
|||
|
P14 --_---_---_-----------_-------_--...
|
|||
|
P15 --_-----------_---_-------_------...
|
|||
|
</pre></td></tr></tbody></table>Data and reset pulses must be kept LOW for at least 5us. P14 and P15
|
|||
|
must be kept both HIGH for at least 15us between any pulses.<br>
|
|||
|
Obviously, it'd be no good idea to access the JOYPAD register during the
|
|||
|
transfer, for example, in case that your VBlank interrupt procedure
|
|||
|
reads-out joypad states each frame, be sure to disable that interrupt
|
|||
|
during the transfer (or disable only the joypad procedure by using a
|
|||
|
software flag).<br>
|
|||
|
<br>
|
|||
|
<b>Transferring Packets<br>
|
|||
|
</b>Each packet is invoked by a RESET pulse, then 128 bits of data are
|
|||
|
transferred (16 bytes, LSB of first byte first), and finally, a "0"-bit
|
|||
|
must be transferred as stop bit. The structure of normal packets is:<br>
|
|||
|
<table><tbody><tr><td><pre> 1 PULSE Reset
|
|||
|
1 BYTE Command Code*8+Length
|
|||
|
15 BYTES Parameter Data
|
|||
|
1 BIT Stop Bit (0)
|
|||
|
</pre></td></tr></tbody></table>The above 'Length' indicates the total number of packets (1-7, including
|
|||
|
the first packet) which will be sent, ie. if more than 15 parameter
|
|||
|
bytes are used, then further packet(s) will follow, as such:<br>
|
|||
|
<table><tbody><tr><td><pre> 1 PULSE Reset
|
|||
|
16 BYTES Parameter Data
|
|||
|
1 BIT Stop Bit (0)
|
|||
|
</pre></td></tr></tbody></table>By using all 7 packets, up to 111 data bytes (15+16*6) may be sent.<br>
|
|||
|
Unused bytes at the end of the last packet must be set to zero.<br>
|
|||
|
A 60ms (4 frames) delay should be invoked between each packet transfer.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbvramtransfers"></a><font size="+2"> SGB VRAM Transfers</font></td></tr></tbody></table><br>
|
|||
|
<b>Overview<br>
|
|||
|
</b>Beside for the packet transfer method, larger data blocks of 4KBytes can
|
|||
|
be transferred by using the video signal. These transfers are invoked by
|
|||
|
first sending one of the commands with the ending _TRN (by using normal
|
|||
|
packet transfer), the 4K data block is then read-out by the SNES from
|
|||
|
gameboy display memory during the next frame.<br>
|
|||
|
<br>
|
|||
|
<b>Transfer Data<br>
|
|||
|
</b>Normally, transfer data should be stored at 8000h-8FFFh in gameboy VRAM,<br>
|
|||
|
even though the SNES receives the data in from display scanlines, it
|
|||
|
will automatically re-produce the same ordering of bits and bytes, as
|
|||
|
being originally stored at 8000h-8FFFh in gameboy memory.<br>
|
|||
|
<br>
|
|||
|
<b>Preparing the Display<br>
|
|||
|
</b>The above method works only when recursing the following things: BG Map
|
|||
|
must display unsigned characters 00h-FFh on the screen; 00h..13h in
|
|||
|
first line, 14h..27h in next line, etc. The gameboy display must be
|
|||
|
enabled, the display may not be scrolled, OBJ sprites should not overlap
|
|||
|
the background tiles, the BGP palette register must be set to E4h.<br>
|
|||
|
<br>
|
|||
|
<b>Transfer Time<br>
|
|||
|
</b>Note that the transfer data should be prepared in VRAM <before> sending
|
|||
|
the transfer command packet. The actual transfer starts at the beginning
|
|||
|
of the next frame after the command has been sent, and the transfer ends
|
|||
|
at the end of the 5th frame after the command has been sent (not
|
|||
|
counting the frame in which the command has been sent).<br>
|
|||
|
<br>
|
|||
|
<b>Avoiding Screen Garbage<br>
|
|||
|
</b>The display will contain 'garbage' during the transfer, this dirt-effect
|
|||
|
can be avoided by freezing the screen (in the state which has been
|
|||
|
displayed before the transfer) by using the MASK_EN command.<br>
|
|||
|
Of course, this works only when actually executing the game on a SGB
|
|||
|
(and not on normal handheld gameboys), it'd be thus required to detect
|
|||
|
the presence of SGB hardware before blindly sending VRAM data.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbcommandsummary"></a><font size="+2"> SGB Command Summary</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB System Command Table<br>
|
|||
|
</b><table><tbody><tr><td><pre> Code Name Expl.
|
|||
|
00 PAL01 Set SGB Palette 0,1 Data
|
|||
|
01 PAL23 Set SGB Palette 2,3 Data
|
|||
|
02 PAL03 Set SGB Palette 0,3 Data
|
|||
|
03 PAL12 Set SGB Palette 1,2 Data
|
|||
|
04 ATTR_BLK "Block" Area Designation Mode
|
|||
|
05 ATTR_LIN "Line" Area Designation Mode
|
|||
|
06 ATTR_DIV "Divide" Area Designation Mode
|
|||
|
07 ATTR_CHR "1CHR" Area Designation Mode
|
|||
|
08 SOUND Sound On/Off
|
|||
|
09 SOU_TRN Transfer Sound PRG/DATA
|
|||
|
0A PAL_SET Set SGB Palette Indirect
|
|||
|
0B PAL_TRN Set System Color Palette Data
|
|||
|
0C ATRC_EN Enable/disable Attraction Mode
|
|||
|
0D TEST_EN Speed Function
|
|||
|
0E ICON_EN SGB Function
|
|||
|
0F DATA_SND SUPER NES WRAM Transfer 1
|
|||
|
10 DATA_TRN SUPER NES WRAM Transfer 2
|
|||
|
11 MLT_REG Controller 2 Request
|
|||
|
12 JUMP Set SNES Program Counter
|
|||
|
13 CHR_TRN Transfer Character Font Data
|
|||
|
14 PCT_TRN Set Screen Data Color Data
|
|||
|
15 ATTR_TRN Set Attribute from ATF
|
|||
|
16 ATTR_SET Set Data to ATF
|
|||
|
17 MASK_EN Game Boy Window Mask
|
|||
|
18 OBJ_TRN Super NES OBJ Mode
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbcolorpalettesoverview"></a><font size="+2"> SGB Color Palettes Overview</font></td></tr></tbody></table><br>
|
|||
|
<b>Available SNES Palettes<br>
|
|||
|
</b>The SGB/SNES provides 8 palettes of 16 colors each, each color may be
|
|||
|
defined out of a selection of 34768 colors (15 bit). Palettes 0-3 are
|
|||
|
used to colorize the gamescreen, only the first four colors of each of
|
|||
|
these palettes are used. Palettes 4-7 are used for the SGB Border, all
|
|||
|
16 colors of each of these palettes may be used.<br>
|
|||
|
<br>
|
|||
|
<b>Color 0 Restriction<br>
|
|||
|
</b>Color 0 of each of the eight palettes is transparent, causing the
|
|||
|
backdrop color to be displayed instead. The backdrop color is typically
|
|||
|
defined by the most recently color being assigned to Color 0 (regardless
|
|||
|
of the palette number being used for that operation).<br>
|
|||
|
Effectively, gamescreen palettes can have only three custom colors each,
|
|||
|
and SGB border palettes only 15 colors each, additionally, color 0 can
|
|||
|
be used for for all palettes, which will then all share the same color
|
|||
|
though.<br>
|
|||
|
<br>
|
|||
|
<b>Translation of Grayshades into Colors<br>
|
|||
|
</b>Because the SGB/SNES reads out the gameboy video controllers display
|
|||
|
signal, it translates the different grayshades from the signal into SNES
|
|||
|
colors as such:<br>
|
|||
|
<table><tbody><tr><td><pre> White --> Color 0
|
|||
|
Light Gray --> Color 1
|
|||
|
Dark Gray --> Color 2
|
|||
|
Black --> Color 3
|
|||
|
</pre></td></tr></tbody></table>Note that gameboy colors 0-3 are assigned to user-selectable grayshades
|
|||
|
by the gameboys BGP, OBP1, and OBP2 registers. There is thus no fixed
|
|||
|
relationship between gameboy colors 0-3 and SNES colors 0-3.<br>
|
|||
|
<br>
|
|||
|
<b>Using Gameboy BGP/OBP Registers<br>
|
|||
|
</b>A direct translation of color 0-3 into color 0-3 may be produced by
|
|||
|
setting BGP/OBP registers to a value of 0E4h each. However, in case that
|
|||
|
your program uses black background for example, then you may internally
|
|||
|
assign background as "White" at the gameboy side by BGP/OBP registers
|
|||
|
(which is then interpreted as SNES color 0, which is shared for all SNES
|
|||
|
palettes). The advantage is that you may define Color 0 as Black at the
|
|||
|
SNES side, and may assign custom colors for Colors 1-3 of each SNES
|
|||
|
palette.<br>
|
|||
|
<br>
|
|||
|
<b>System Color Palette Memory<br>
|
|||
|
</b>Beside for the actually visible palettes, up to 512 palettes of 4 colors
|
|||
|
each may be defined in SNES RAM. Basically, this is completely
|
|||
|
irrelevant because the palettes are just stored in RAM whithout any
|
|||
|
relationship to the displayed picture, anyways, these pre-defined colors
|
|||
|
may be transferred to actually visible palettes slightly faster as when
|
|||
|
transferring palette data by separate command packets.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbpalettecommands"></a><font size="+2"> SGB Palette Commands</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 00h - PAL01<br>
|
|||
|
</b>Transmit color data for SGB palette 0, color 0-3, and for SGB palette 1,
|
|||
|
color 1-3 (without separate color 0).<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=01h)
|
|||
|
1-E Color Data for 7 colors of 2 bytes (16bit) each:
|
|||
|
Bit 0-4 - Red Intensity (0-31)
|
|||
|
Bit 5-9 - Green Intensity (0-31)
|
|||
|
Bit 10-14 - Blue Intensity (0-31)
|
|||
|
Bit 15 - Not used (zero)
|
|||
|
F Not used (00h)
|
|||
|
</pre></td></tr></tbody></table>The value transferred as color 0 will be applied for all eight palettes.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 01h - PAL23<br>
|
|||
|
</b>Same as above PAL01, but for Palettes 2 and 3 respectively.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 02h - PAL03<br>
|
|||
|
</b>Same as above PAL01, but for Palettes 0 and 3 respectively.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 03h - PAL12<br>
|
|||
|
</b>Same as above PAL01, but for Palettes 1 and 2 respectively.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 0Ah - PAL_SET<br>
|
|||
|
</b>Used to copy pre-defined palette data from SGB system color palette to
|
|||
|
actual SGB palette.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1-2 System Palette number for SGB Color Palette 0 (0-511)
|
|||
|
3-4 System Palette number for SGB Color Palette 1 (0-511)
|
|||
|
5-6 System Palette number for SGB Color Palette 2 (0-511)
|
|||
|
7-8 System Palette number for SGB Color Palette 3 (0-511)
|
|||
|
9 Attribute File
|
|||
|
Bit 0-5 - Attribute File Number (00h-2Ch) (Used only if Bit7=1)
|
|||
|
Bit 6 - Cancel Mask (0=No change, 1=Yes)
|
|||
|
Bit 7 - Use Attribute File (0=No, 1=Apply above ATF Number)
|
|||
|
A-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>Before using this function, System Palette data should be initialized by
|
|||
|
PAL_TRN command, and (when used) Attribute File data should be
|
|||
|
initialized by ATTR_TRN.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 0Bh - PAL_TRN<br>
|
|||
|
</b>Used to initialize SGB system color palettes in SNES RAM.<br>
|
|||
|
System color palette memory contains 512 pre-defined palettes, these
|
|||
|
palettes do not directly affect the display, however, the PAL_SET
|
|||
|
command may be later used to transfer four of these 'logical' palettes
|
|||
|
to actual visible 'physical' SGB palettes. Also, the OBJ_TRN function
|
|||
|
will use groups of 4 System Color Palettes (4*4 colors) for SNES OBJ
|
|||
|
palettes (16 colors).<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The palette data is sent by VRAM-Transfer (4 KBytes).<br>
|
|||
|
<table><tbody><tr><td><pre> 000-FFF Data for System Color Palette 0-511
|
|||
|
</pre></td></tr></tbody></table>Each Palette consists of four 16bit-color definitions (8 bytes).<br>
|
|||
|
Note: The data is stored at 3000h-3FFFh in SNES memory.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbcolorattributecommands"></a><font size="+2"> SGB Color Attribute Commands</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 04h - ATTR_BLK<br>
|
|||
|
</b>Used to specify color attributes for the inside or outside of one or
|
|||
|
more rectangular screen regions.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (length=1..7)
|
|||
|
1 Number of Data Sets (01h..12h)
|
|||
|
2-7 Data Set #1
|
|||
|
Byte 0 - Control Code (0-7)
|
|||
|
Bit 0 - Change Colors inside of surrounded area (1=Yes)
|
|||
|
Bit 1 - Change Colors of surrounding character line (1=Yes)
|
|||
|
Bit 2 - Change Colors outside of surrounded area (1=Yes)
|
|||
|
Bit 3-7 - Not used (zero)
|
|||
|
Exception: When changing only the Inside or Outside, then the
|
|||
|
Surrounding line becomes automatically changed to same color.
|
|||
|
Byte 1 - Color Palette Designation
|
|||
|
Bit 0-1 - Palette Number for inside of surrounded area
|
|||
|
Bit 2-3 - Palette Number for surrounding character line
|
|||
|
Bit 4-5 - Palette Number for outside of surrounded area
|
|||
|
Bit 6-7 - Not used (zero)
|
|||
|
Data Set Byte 2 - Coordinate X1 (left)
|
|||
|
Data Set Byte 3 - Coordinate Y1 (upper)
|
|||
|
Data Set Byte 4 - Coordinate X2 (right)
|
|||
|
Data Set Byte 5 - Coordinate Y2 (lower)
|
|||
|
Specifies the coordinates of the surrounding rectangle.
|
|||
|
8-D Data Set #2 (if any)
|
|||
|
E-F Data Set #3 (continued at 0-3 in next packet) (if any)
|
|||
|
</pre></td></tr></tbody></table>When sending three or more data sets, data is continued in further
|
|||
|
packet(s). Unused bytes at the end of the last packet should be set to
|
|||
|
zero. The format of the separate Data Sets is described below.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 05h - ATTR_LIN<br>
|
|||
|
</b>Used to specify color attributes of one or more horizontal or vertical
|
|||
|
character lines.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (length=1..7)
|
|||
|
1 Number of Data Sets (01h..6Eh) (one byte each)
|
|||
|
2 Data Set #1
|
|||
|
Bit 0-4 - Line Number (X- or Y-coordinate, depending on bit 7)
|
|||
|
Bit 5-6 - Palette Number (0-3)
|
|||
|
Bit 7 - H/V Mode Bit (0=Vertical line, 1=Horizontal Line)
|
|||
|
3 Data Set #2 (if any)
|
|||
|
4 Data Set #3 (if any)
|
|||
|
etc.
|
|||
|
</pre></td></tr></tbody></table>When sending 15 or more data sets, data is continued in further
|
|||
|
packet(s). Unused bytes at the end of the last packet should be set to
|
|||
|
zero. The format of the separate Data Sets (one byte each) is described
|
|||
|
below.<br>
|
|||
|
The length of each line reaches from one end of the screen to the other
|
|||
|
end. In case that some lines overlap each other, then lines from
|
|||
|
lastmost data sets will overwrite lines from previous data sets.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 06h - ATTR_DIV<br>
|
|||
|
</b>Used to split the screen into two halfes, and to assign separate color
|
|||
|
attributes to each half, and to the division line between them.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Color Palette Numbers and H/V Mode Bit
|
|||
|
Bit 0-1 Palette Number below/right of division line
|
|||
|
Bit 2-3 Palette Number above/left of division line
|
|||
|
Bit 4-5 Palette Number for division line
|
|||
|
Bit 6 H/V Mode Bit (0=split left/right, 1=split above/below)
|
|||
|
2 X- or Y-Coordinate (depending on H/V bit)
|
|||
|
3-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 07h - ATTR_CHR<br>
|
|||
|
</b>Used to specify color attributes for separate characters.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (length=1..6)
|
|||
|
1 Beginning X-Coordinate
|
|||
|
2 Beginning Y-Coordinate
|
|||
|
3-4 Number of Data Sets (1-360)
|
|||
|
5 Writing Style (0=Left to Right, 1=Top to Bottom)
|
|||
|
6 Data Sets 1-4 (Set 1 in MSBs, Set 4 in LSBs)
|
|||
|
7 Data Sets 5-8 (if any)
|
|||
|
8 Data Sets 9-12 (if any)
|
|||
|
etc.
|
|||
|
</pre></td></tr></tbody></table>When sending 41 or more data sets, data is continued in further
|
|||
|
packet(s). Unused bytes at the end of the last packet should be set to
|
|||
|
zero. Each data set consists of two bits, indicating the palette number
|
|||
|
for one character.<br>
|
|||
|
Depending on the writing style, data sets are written from left to
|
|||
|
right, or from top to bottom. In either case the function wraps to the
|
|||
|
next row/column when reaching the end of the screen.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 15h - ATTR_TRN<br>
|
|||
|
</b>Used to initialize Attribute Files (ATFs) in SNES RAM. Each ATF consists
|
|||
|
of 20x18 color attributes for the gameboy screen. This function does not
|
|||
|
directly affect display attributes. Instead, one of the defined ATFs may
|
|||
|
be copied to actual display memory at a later time by using ATTR_SET or
|
|||
|
PAL_SET functions.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The ATF data is sent by VRAM-Transfer (4 KBytes).<br>
|
|||
|
<table><tbody><tr><td><pre> 000-FD1 Data for ATF0 through ATF44 (4050 bytes)
|
|||
|
FD2-FFF Not used
|
|||
|
</pre></td></tr></tbody></table>Each ATF consists of 90 bytes, that are 5 bytes (20x2bits) for each of
|
|||
|
the 18 character lines of the gameboy window. The two most significant
|
|||
|
bits of the first byte define the color attribute (0-3) for the first
|
|||
|
character of the first line, the next two bits the next character, and
|
|||
|
so on.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 16h - ATTR_SET<br>
|
|||
|
</b>Used to transfer attributes from Attribute File (ATF) to gameboy window.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Attribute File Number (00-2Ch), Bit 6=Cancel Mask
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>When above Bit 6 is set, the gameboy screen becomes re-enabled after the
|
|||
|
transfer (in case it has been disabled/frozen by MASK_EN command).<br>
|
|||
|
Note: The same functions may be (optionally) also included in PAL_SET
|
|||
|
commands, as described in the chapter about Color Palette Commands.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbsoundfunctions"></a><font size="+2"> SGB Sound Functions</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 08h - SOUND<br>
|
|||
|
</b>Used to start/stop internal sound effect, start/stop sound using
|
|||
|
internal tone data.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Sound Effect A (Port 1) Decrescendo 8bit Sound Code
|
|||
|
2 Sound Effect B (Port 2) Sustain 8bit Sound Code
|
|||
|
3 Sound Effect Attributes
|
|||
|
Bit 0-1 - Sound Effect A Pitch (0..3=Low..High)
|
|||
|
Bit 2-3 - Sound Effect A Volume (0..2=High..Low, 3=Mute on)
|
|||
|
Bit 4-5 - Sound Effect B Pitch (0..3=Low..High)
|
|||
|
Bit 6-7 - Sound Effect B Volume (0..2=High..Low, 3=Not used)
|
|||
|
4 Music Score Code (must be zero if not used)
|
|||
|
5-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>See Sound Effect Tables below for a list of available pre-defined effects.<br>
|
|||
|
"Notes"<br>
|
|||
|
1) Mute is only active when both bits D2 and D3 are 1.<br>
|
|||
|
2) When the volume is set for either Sound Effect A or Sound Effect B,
|
|||
|
mute is turned off.<br>
|
|||
|
3) When Mute on/off has been executed, the sound fades out/fades in.<br>
|
|||
|
4) Mute on/off operates on the (BGM) which is reproduced by Sound Effect
|
|||
|
A, Sound Effect B, and the Super NES APU. A "mute off" flag does not
|
|||
|
exist by itself. When mute flag is set, volume and pitch of Sound Effect
|
|||
|
A (port 1) and Sound Effect B (port 2) must be set.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 09h - SOU_TRN<br>
|
|||
|
</b>Used to transfer sound code or data to SNES Audio Processing Unit memory
|
|||
|
(APU-RAM).<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The sound code/data is sent by VRAM-Transfer (4 KBytes).<br>
|
|||
|
<table><tbody><tr><td><pre> 000 One (or two ???) 16bit expression(s ???) indicating the
|
|||
|
transfer destination address and transfer length.
|
|||
|
...-... Transfer Data
|
|||
|
...-FFF Remaining bytes not used
|
|||
|
</pre></td></tr></tbody></table>Possible destinations in APU-RAM are:<br>
|
|||
|
<table><tbody><tr><td><pre> 0400h-2AFFh APU-RAM Program Area (9.75KBytes)
|
|||
|
2B00h-4AFFh APU-RAM Sound Score Area (8Kbytes)
|
|||
|
4DB0h-EEFFh APU-RAM Sampling Data Area (40.25 Kbytes)
|
|||
|
</pre></td></tr></tbody></table>This function may be used to take control of the SNES sound chip, and/or
|
|||
|
to access the SNES MIDI engine. In either case it requires deeper
|
|||
|
knowledge of SNES sound programming.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Sound Effect A/B Tables<br>
|
|||
|
</b>Below lists the digital sound effects that are pre-defined in the
|
|||
|
SGB/SNES BIOS, and which can be used with the SGB "SOUND" Command.<br>
|
|||
|
Effect A and B may be simultaneously reproduced.<br>
|
|||
|
The P-column indicates the recommended Pitch value, the V-column
|
|||
|
indicates the numbers of Voices used. Sound Effect A uses voices 6,7.
|
|||
|
Sound Effect B uses voices 0,1,4,5. Effects that use less voices will
|
|||
|
use only the upper voices (eg. 4,5 for Effect B with only two voices).<br>
|
|||
|
<br>
|
|||
|
<b>Sound Effect A Flag Table<br>
|
|||
|
</b><table><tbody><tr><td><pre> Code Description P V Code Description P V
|
|||
|
00 Dummy flag, re-trigger - 2 18 Fast Jump 3 1
|
|||
|
80 Effect A, stop/silent - 2 19 Jet (rocket) takeoff 0 1
|
|||
|
01 Nintendo 3 1 1A Jet (rocket) landing 0 1
|
|||
|
02 Game Over 3 2 1B Cup breaking 2 2
|
|||
|
03 Drop 3 1 1C Glass breaking 1 2
|
|||
|
04 OK ... A 3 2 1D Level UP 2 2
|
|||
|
05 OK ... B 3 2 1E Insert air 1 1
|
|||
|
06 Select...A 3 2 1F Sword swing 1 1
|
|||
|
07 Select...B 3 1 20 Water falling 2 1
|
|||
|
08 Select...C 2 2 21 Fire 1 1
|
|||
|
09 Mistake...Buzzer 2 1 22 Wall collapsing 1 2
|
|||
|
0A Catch Item 2 2 23 Cancel 1 2
|
|||
|
0B Gate squeaks 1 time 2 2 24 Walking 1 2
|
|||
|
0C Explosion...small 1 2 25 Blocking strike 1 2
|
|||
|
0D Explosion...medium 1 2 26 Picture floats on & off 3 2
|
|||
|
0E Explosion...large 1 2 27 Fade in 0 2
|
|||
|
0F Attacked...A 3 1 28 Fade out 0 2
|
|||
|
10 Attacked...B 3 2 29 Window being opened 1 2
|
|||
|
11 Hit (punch)...A 0 2 2A Window being closed 0 2
|
|||
|
12 Hit (punch)...B 0 2 2B Big Laser 3 2
|
|||
|
13 Breath in air 3 2 2C Stone gate closes/opens 0 2
|
|||
|
14 Rocket Projectile...A 3 2 2D Teleportation 3 1
|
|||
|
15 Rocket Projectile...B 3 2 2E Lightning 0 2
|
|||
|
16 Escaping Bubble 2 1 2F Earthquake 0 2
|
|||
|
17 Jump 3 1 30 Small Laser 2 2
|
|||
|
</pre></td></tr></tbody></table>Sound effect A is used for formanto sounds (percussion sounds).<br>
|
|||
|
<br>
|
|||
|
<b>Sound Effect B Flag Table<br>
|
|||
|
</b><table><tbody><tr><td><pre> Code Description P V Code Description P V
|
|||
|
00 Dummy flag, re-trigger - 4 0D Waterfall 2 2
|
|||
|
80 Effect B, stop/silent - 4 0E Small character running 3 1
|
|||
|
01 Applause...small group 2 1 0F Horse running 3 1
|
|||
|
02 Applause...medium group 2 2 10 Warning sound 1 1
|
|||
|
03 Applause...large group 2 4 11 Approaching car 0 1
|
|||
|
04 Wind 1 2 12 Jet flying 1 1
|
|||
|
05 Rain 1 1 13 UFO flying 2 1
|
|||
|
06 Storm 1 3 14 Electromagnetic waves 0 1
|
|||
|
07 Storm with wind/thunder 2 4 15 Score UP 3 1
|
|||
|
08 Lightning 0 2 16 Fire 2 1
|
|||
|
09 Earthquake 0 2 17 Camera shutter, formanto 3 4
|
|||
|
0A Avalanche 0 2 18 Write, formanto 0 1
|
|||
|
0B Wave 0 1 19 Show up title, formanto 0 1
|
|||
|
0C River 3 2
|
|||
|
</pre></td></tr></tbody></table>Sound effect B is mainly used for looping sounds (sustained sounds).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbsystemcontrolcommands"></a><font size="+2"> SGB System Control Commands</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 17h - MASK_EN<br>
|
|||
|
</b>Used to mask the gameboy window, among others this can be used to freeze
|
|||
|
the gameboy screen before transferring data through VRAM (the SNES then
|
|||
|
keeps displaying the gameboy screen, even though VRAM doesn't contain
|
|||
|
meaningful display information during the transfer).<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Gameboy Screen Mask (0-3)
|
|||
|
0 Cancel Mask (Display activated)
|
|||
|
1 Freeze Screen (Keep displaying current picture)
|
|||
|
2 Blank Screen (Black)
|
|||
|
3 Blank Screen (Color 0)
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>Freezing works only if the SNES has stored a picture, ie. if necessary
|
|||
|
wait one or two frames before freezing (rather than freezing directly
|
|||
|
after having displayed the picture).<br>
|
|||
|
The Cancel Mask function may be also invoked (optionally) by completion
|
|||
|
of PAL_SET and ATTR_SET commands.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 0Ch - ATRC_EN<br>
|
|||
|
</b>Used to enable/disable Attraction mode. It is totally unclear what an
|
|||
|
attraction mode is ???, but it is enabled by default.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Attraction Disable (0=Enable, 1=Disable)
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 0Dh - TEST_EN<br>
|
|||
|
</b>Used to enable/disable test mode for "SGB-CPU variable clock speed
|
|||
|
function". This function is disabled by default.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Test Mode Enable (0=Disable, 1=Enable)
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>Maybe intended to determine whether SNES operates at 50Hz or 60Hz
|
|||
|
display refresh rate ??? Possibly result can be read-out from joypad
|
|||
|
register ???<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 0Eh - ICON_EN<br>
|
|||
|
</b>Used to enable/disable ICON function. Possibly meant to enable/disable
|
|||
|
SGB/SNES popup menues which might otherwise activated during gameboy
|
|||
|
game play. By default all functions are enabled (0).<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Disable Bits
|
|||
|
Bit 0 - Use of SGB-Built-in Color Palettes (1=Disable)
|
|||
|
Bit 1 - Controller Set-up Screen (0=Enable, 1=Disable)
|
|||
|
Bit 2 - SGB Register File Transfer (0=Receive, 1=Disable)
|
|||
|
Bit 3-6 - Not used (zero)
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>Above Bit 2 will suppress all further packets/commands when set, this
|
|||
|
might be useful when starting a monochrome game from inside of the
|
|||
|
SGB-menu of a multi-gamepak which contains a collection of different
|
|||
|
games.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 0Fh - DATA_SND<br>
|
|||
|
</b>Used to write one or more bytes directly into SNES Work RAM.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 SNES Destination Address, low
|
|||
|
2 SNES Destination Address, high
|
|||
|
3 SNES Destination Address, bank number
|
|||
|
4 Number of bytes to write (01h-0Bh)
|
|||
|
5 Data Byte #1
|
|||
|
6 Data Byte #2 (if any)
|
|||
|
7 Data Byte #3 (if any)
|
|||
|
etc.
|
|||
|
</pre></td></tr></tbody></table>Unused bytes at the end of the packet should be set to zero, this
|
|||
|
function is restricted to a single packet, so that not more than 11
|
|||
|
bytes can be defined at once.<br>
|
|||
|
Free Addresses in SNES memory are Bank 0 1800h-1FFFh, Bank 7Fh
|
|||
|
0000h-FFFFh.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 10h - DATA_TRN<br>
|
|||
|
</b>Used to transfer binary code or data directly into SNES RAM.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 SNES Destination Address, low
|
|||
|
2 SNES Destination Address, high
|
|||
|
3 SNES Destination Address, bank number
|
|||
|
4-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The data is sent by VRAM-Transfer (4 KBytes).<br>
|
|||
|
<table><tbody><tr><td><pre> 000-FFF Data
|
|||
|
</pre></td></tr></tbody></table>Free Addresses in SNES memory are Bank 0 1800h-1FFFh, Bank 7Fh
|
|||
|
0000h-FFFFh. The transfer length is fixed at 4KBytes ???, so that directly
|
|||
|
writing to the free 2KBytes at 0:1800h would be a not so good idea ???<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 12h - JUMP<br>
|
|||
|
</b>Used to set the SNES program counter to a specified address. Optionally,
|
|||
|
it may be used to set a new address for the SNES NMI handler, the NMI
|
|||
|
handler remains unchanged if all bytes 4-6 are zero.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 SNES Program Counter, low
|
|||
|
2 SNES Program Counter, high
|
|||
|
3 SNES Program Counter, bank number
|
|||
|
4 SNES NMI Handler, low
|
|||
|
5 SNES NMI Handler, high
|
|||
|
6 SNES NMI Handler, bank number
|
|||
|
7-F Not used, zero
|
|||
|
</pre></td></tr></tbody></table>Note: The game "Space Invaders 94" uses this function when selecting
|
|||
|
"Arcade mode" to execute SNES program code which has been previously
|
|||
|
transferred from the SGB to the SNES. The type of the CPU which is used
|
|||
|
in the SNES is unknown ???<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbmultiplayercommand"></a><font size="+2"> SGB Multiplayer Command</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 11h - MLT_REQ<br>
|
|||
|
</b>Used to request multiplayer mode (ie. input from more than one joypad).<br>
|
|||
|
Because this function provides feedback from the SGB/SNES to the gameboy
|
|||
|
program, it is also used to detect SGB hardware.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Multiplayer Control (0-3) (Bit0=Enable, Bit1=Two/Four Players)
|
|||
|
0 = One player
|
|||
|
1 = Two players
|
|||
|
3 = Four players
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>In one player mode, the second joypad (if any) is used for the SGB
|
|||
|
system program. In two player mode, both joypads are used for the game.
|
|||
|
Because SNES have only two joypad sockets, four player mode requires an
|
|||
|
external "Multiplayer 5" adapter.<br>
|
|||
|
<br>
|
|||
|
<b>Reading Multiple Controllers (Joypads)<br>
|
|||
|
</b>When having enabled multiple controllers by MLT_REQ, data for each
|
|||
|
joypad can be read out through JOYPAD register (FF00) as follows: First
|
|||
|
set P14 and P15 both HIGH (deselect both Buttons and Cursor keys), you
|
|||
|
can now read the lower 4bits of FF00 which indicate the joypad ID for
|
|||
|
the following joypad input:<br>
|
|||
|
<table><tbody><tr><td><pre> 0Fh Joypad 1
|
|||
|
0Eh Joypad 2
|
|||
|
0Dh Joypad 3
|
|||
|
0Ch Joypad 4
|
|||
|
</pre></td></tr></tbody></table>Next, set P14 and P15 low (one after each other) to select Buttons and
|
|||
|
Cursor lines, and read-out joypad state as normally. When completed, set
|
|||
|
P14 and P15 back HIGH, this automatically increments the joypad number
|
|||
|
(or restarts counting once reached the lastmost joypad). Repeat the
|
|||
|
procedure until you have read-out states for all two (or four) joypads.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="sgbborderandobjcommands"></a><font size="+2"> SGB Border and OBJ Commands</font></td></tr></tbody></table><br>
|
|||
|
<b>SGB Command 13h - CHR_TRN<br>
|
|||
|
</b>Used to transfer tile data (characters) to SNES Tile memory in VRAM. This
|
|||
|
normally used to define BG tiles for the SGB Border (see PCT_TRN), but
|
|||
|
might be also used to define moveable SNES foreground sprites (see
|
|||
|
OBJ_TRN).<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Tile Transfer Destination
|
|||
|
Bit 0 - Tile Numbers (0=Tiles 00h-7Fh, 1=Tiles 80h-FFh)
|
|||
|
Bit 1 - Tile Type (0=BG Tiles, 1=OBJ Tiles)
|
|||
|
Bit 2-7 - Not used (zero)
|
|||
|
2-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The tile data is sent by VRAM-Transfer (4 KBytes).<br>
|
|||
|
<table><tbody><tr><td><pre> 000-FFF Bitmap data for 128 Tiles
|
|||
|
</pre></td></tr></tbody></table>Each tile occupies 16bytes (8x8 pixels, 16 colors each).<br>
|
|||
|
When intending to transfer more than 128 tiles, call this function twice
|
|||
|
(once for tiles 00h-7Fh, and once for tiles 80h-FFh). Note: The BG/OBJ
|
|||
|
Bit seems to have no effect and writes to the same VRAM addresses for
|
|||
|
both BG and OBJ ???<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 14h - PCT_TRN<br>
|
|||
|
</b>Used to transfer tile map data and palette data to SNES BG Map memory in
|
|||
|
VRAM to be used for the SGB border. The actual tiles must be separately
|
|||
|
transferred by using the CHR_TRN function.<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The map data is sent by VRAM-Transfer (4 KBytes).<br>
|
|||
|
<table><tbody><tr><td><pre> 000-7FF BG Map 32x32 Entries of 16bit each (2048 bytes)
|
|||
|
800-87F BG Palette Data (Palettes 4-7, each 16 colors of 16bits each)
|
|||
|
880-FFF Not used, don't care
|
|||
|
</pre></td></tr></tbody></table>Each BG Map Entry consists of a 16bit value as such:<br>
|
|||
|
<table><tbody><tr><td><pre> Bit 0-9 - Character Number (use only 00h-FFh, upper 2 bits zero)
|
|||
|
Bit 10-12 - Palette Number (use only 4-7, officially use only 4-6)
|
|||
|
Bit 13 - BG Priority (use only 0)
|
|||
|
Bit 14 - X-Flip (0=Normal, 1=Mirror horizontally)
|
|||
|
Bit 15 - Y-Flip (0=Normal, 1=Mirror vertically)
|
|||
|
</pre></td></tr></tbody></table>Even though 32x32 map entries are transferred, only upper 32x28 are
|
|||
|
actually used (256x224 pixels, SNES screen size). The 20x18 entries in
|
|||
|
the center of the 32x28 area should be set to 0000h as transparent space
|
|||
|
for the gameboy window to be displayed inside. Reportedly,
|
|||
|
non-transparent border data will cover the gameboy window.<br>
|
|||
|
<br>
|
|||
|
<b>SGB Command 18h - OBJ_TRN<br>
|
|||
|
</b>Used to transfer OBJ attributes to SNES OAM memory. Unlike all other
|
|||
|
functions with the ending _TRN, this function does not use the usual
|
|||
|
one-shot 4KBytes VRAM transfer method.<br>
|
|||
|
Instead, when enabled (below execute bit set), data is permanently (each
|
|||
|
frame) read out from the lower character line of the gameboy screen. To
|
|||
|
suppress garbage on the display, the lower line is masked, and only the
|
|||
|
upper 20x17 characters of the gameboy window are used - the masking
|
|||
|
method is unknwon - frozen, black, or recommended to be covered by the
|
|||
|
SGB border, or else ??? Also, when the function is enabled, "system
|
|||
|
attract mode is not performed" - whatever that means ???<br>
|
|||
|
<table><tbody><tr><td><pre> Byte Content
|
|||
|
0 Command*8+Length (fixed length=1)
|
|||
|
1 Control Bits
|
|||
|
Bit 0 - SNES OBJ Mode enable (0=Cancel, 1=Enable)
|
|||
|
Bit 1 - Change OBJ Color (0=No, 1=Use definitions below)
|
|||
|
Bit 2-7 - Not used (zero)
|
|||
|
2-3 System Color Palette Number for OBJ Palette 4 (0-511)
|
|||
|
4-5 System Color Palette Number for OBJ Palette 5 (0-511)
|
|||
|
6-7 System Color Palette Number for OBJ Palette 6 (0-511)
|
|||
|
8-9 System Color Palette Number for OBJ Palette 7 (0-511)
|
|||
|
These color entries are ignored if above Control Bit 1 is zero.
|
|||
|
Because each OBJ palette consists of 16 colors, four system
|
|||
|
palette entries (of 4 colors each) are transferred into each
|
|||
|
OBJ palette. The system palette numbers are not required to be
|
|||
|
aligned to a multiple of four, and will wrap to palette number
|
|||
|
0 when exceeding 511. For example, a value of 511 would copy
|
|||
|
system palettes 511, 0, 1, 2 to the SNES OBJ palette.
|
|||
|
A-F Not used (zero)
|
|||
|
</pre></td></tr></tbody></table>The recommended method is to "display" gameboy BG tiles F9h..FFh from
|
|||
|
left to right as first 7 characters of the bottom-most character line of
|
|||
|
the gameboy screen. As for normal 4KByte VRAM transfers, this area
|
|||
|
should not be scrolled, should not be overlapped by gameboy OBJs, and
|
|||
|
the gameboy BGP palette register should be set up properly. By following
|
|||
|
that method, SNES OAM data can be defined in the 70h bytes of the
|
|||
|
gameboy BG tile memory at following addresses:<br>
|
|||
|
<table><tbody><tr><td><pre> 8F90-8FEF SNES OAM, 24 Entries of 4 bytes each (96 bytes)
|
|||
|
8FF0-8FF5 SNES OAM MSBs, 24 Entries of 2 bits each (6 bytes)
|
|||
|
8FF6-8FFF Not used, don't care (10 bytes)
|
|||
|
</pre></td></tr></tbody></table>The format of SNES OAM Entries is:<br>
|
|||
|
<table><tbody><tr><td><pre> Byte 0 OBJ X-Position (0-511, MSB is separately stored, see below)
|
|||
|
Byte 1 OBJ Y-Position (0-255)
|
|||
|
Byte 2-3 Attributes (16bit)
|
|||
|
Bit 0-8 Tile Number (use only 00h-FFh, upper bit zero)
|
|||
|
Bit 9-11 Palette Number (use only 4-7)
|
|||
|
Bit 12-13 OBJ Priority (use only 3)
|
|||
|
Bit 14 X-Flip (0=Normal, 1=Mirror horizontally)
|
|||
|
Bit 15 Y-Flip (0=Normal, 1=Mirror vertically)
|
|||
|
</pre></td></tr></tbody></table>The format of SNES OAM MSB Entries is:<br>
|
|||
|
<table><tbody><tr><td><pre> Actually, the format is unknown ??? However, 2 bits are used per entry:
|
|||
|
One bit is the most significant bit of the OBJ X-Position.
|
|||
|
The other bit specifies the OBJ size (8x8 or 16x16 pixels).
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="cpuregistersandflags"></a><font size="+2"> CPU Registers and Flags</font></td></tr></tbody></table><br>
|
|||
|
<b>Registers<br>
|
|||
|
</b><table><tbody><tr><td><pre> 16bit Hi Lo Name/Function
|
|||
|
AF A - Accumulator & Flags
|
|||
|
BC B C BC
|
|||
|
DE D E DE
|
|||
|
HL H L HL
|
|||
|
SP - - Stack Pointer
|
|||
|
PC - - Program Counter/Pointer
|
|||
|
</pre></td></tr></tbody></table>As shown above, most registers can be accessed either as one 16bit
|
|||
|
register, or as two separate 8bit registers.<br>
|
|||
|
<br>
|
|||
|
<b>The Flag Register (lower 8bit of AF register)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Bit Name Set Clr Expl.
|
|||
|
7 zf Z NZ Zero Flag
|
|||
|
6 n - - Add/Sub-Flag (BCD)
|
|||
|
5 h - - Half Carry Flag (BCD)
|
|||
|
4 cy C NC Carry Flag
|
|||
|
3-0 - - - Not used (always zero)
|
|||
|
</pre></td></tr></tbody></table>Conatins the result from the recent instruction which has affected
|
|||
|
flags.<br>
|
|||
|
<br>
|
|||
|
<b>The Zero Flag (Z)<br>
|
|||
|
</b>This bit becomes set (1) if the result of an operation has been zero
|
|||
|
(0). Used for conditional jumps.<br>
|
|||
|
<br>
|
|||
|
<b>The Carry Flag (C, or Cy)<br>
|
|||
|
</b>Becomes set when the result of an addition became bigger than FFh (8bit)
|
|||
|
or FFFFh (16bit). Or when the result of a subtraction or comparision
|
|||
|
became less than zero (much as for Z80 and 80x86 CPUs, but unlike as for
|
|||
|
65XX and ARM CPUs). Also the flag becomes set when a rotate/shift
|
|||
|
operation has shifted-out a "1"-bit.<br>
|
|||
|
Used for conditional jumps, and for instructions such like ADC, SBC, RL,
|
|||
|
RLA, etc.<br>
|
|||
|
<br>
|
|||
|
<b>The BCD Flags (N, H)<br>
|
|||
|
</b>These flags are (rarely) used for the DAA instruction only, N Indicates
|
|||
|
whether the previous instruction has been an addition or subtraction,
|
|||
|
and H indicates carry for lower 4bits of the result, also for DAA, the C
|
|||
|
flag must indicate carry for upper 8bits.<br>
|
|||
|
After adding/subtracting two BCD numbers, DAA is intended to convert the
|
|||
|
result into BCD format; BCD numbers are ranged from 00h to 99h rather
|
|||
|
than 00h to FFh.<br>
|
|||
|
Because C and H flags must contain carry-outs for each digit, DAA cannot
|
|||
|
be used for 16bit operations (which have 4 digits), or for INC/DEC
|
|||
|
operations (which do not affect C-flag).<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="cpuinstructionset"></a><font size="+2"> CPU Instruction Set</font></td></tr></tbody></table><br>
|
|||
|
Tables below specify the mnemonic, opcode bytes, clock cycles, affected
|
|||
|
flags (ordered as znhc), and explanatation.<br>
|
|||
|
The timings assume a CPU clock frequency of 4.194304 MHz (or 8.4<br>
|
|||
|
MHz for CGB in double speed mode), as all gameboy timings are divideable<br>
|
|||
|
by 4, many people specify timings and clock frequency divided by 4.<br>
|
|||
|
<br>
|
|||
|
<b>GMB 8bit-Loadcommands<br>
|
|||
|
</b><table><tbody><tr><td><pre> ld r,r xx 4 ---- r=r
|
|||
|
ld r,n xx nn 8 ---- r=n
|
|||
|
ld r,(HL) xx 8 ---- r=(HL)
|
|||
|
ld (HL),r 7x 8 ---- (HL)=r
|
|||
|
ld (HL),n 36 nn 12 ----
|
|||
|
ld A,(BC) 0A 8 ----
|
|||
|
ld A,(DE) 1A 8 ----
|
|||
|
ld A,(nn) FA 16 ----
|
|||
|
ld (BC),A 02 8 ----
|
|||
|
ld (DE),A 12 8 ----
|
|||
|
ld (nn),A EA 16 ----
|
|||
|
ld A,(FF00+n) F0 nn 12 ---- read from io-port n (memory FF00+n)
|
|||
|
ld (FF00+n),A E0 nn 12 ---- write to io-port n (memory FF00+n)
|
|||
|
ld A,(FF00+C) F2 8 ---- read from io-port C (memory FF00+C)
|
|||
|
ld (FF00+C),A E2 8 ---- write to io-port C (memory FF00+C)
|
|||
|
ldi (HL),A 22 8 ---- (HL)=A, HL=HL+1
|
|||
|
ldi A,(HL) 2A 8 ---- A=(HL), HL=HL+1
|
|||
|
ldd (HL),A 32 8 ---- (HL)=A, HL=HL-1
|
|||
|
ldd A,(HL) 3A 8 ---- A=(HL), HL=HL-1
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB 16bit-Loadcommands<br>
|
|||
|
</b><table><tbody><tr><td><pre> ld rr,nn x1 nn nn 12 ---- rr=nn (rr may be BC,DE,HL or SP)
|
|||
|
ld SP,HL F9 8 ---- SP=HL
|
|||
|
push rr x5 16 ---- SP=SP-2 (SP)=rr (rr may be BC,DE,HL,AF)
|
|||
|
pop rr x1 12 (AF) rr=(SP) SP=SP+2 (rr may be BC,DE,HL,AF)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB 8bit-Arithmetic/logical Commands<br>
|
|||
|
</b><table><tbody><tr><td><pre> add A,r 8x 4 z0hc A=A+r
|
|||
|
add A,n C6 nn 8 z0hc A=A+n
|
|||
|
add A,(HL) 86 8 z0hc A=A+(HL)
|
|||
|
adc A,r 8x 4 z0hc A=A+r+cy
|
|||
|
adc A,n CE nn 8 z0hc A=A+n+cy
|
|||
|
adc A,(HL) 8E 8 z0hc A=A+(HL)+cy
|
|||
|
sub r 9x 4 z1hc A=A-r
|
|||
|
sub n D6 nn 8 z1hc A=A-n
|
|||
|
sub (HL) 96 8 z1hc A=A-(HL)
|
|||
|
sbc A,r 9x 4 z1hc A=A-r-cy
|
|||
|
sbc A,n DE nn 8 z1hc A=A-n-cy
|
|||
|
sbc A,(HL) 9E 8 z1hc A=A-(HL)-cy
|
|||
|
and r Ax 4 z010 A=A & r
|
|||
|
and n E6 nn 8 z010 A=A & n
|
|||
|
and (HL) A6 8 z010 A=A & (HL)
|
|||
|
xor r Ax 4 z000
|
|||
|
xor n EE nn 8 z000
|
|||
|
xor (HL) AE 8 z000
|
|||
|
or r Bx 4 z000 A=A | r
|
|||
|
or n F6 nn 8 z000 A=A | n
|
|||
|
or (HL) B6 8 z000 A=A | (HL)
|
|||
|
cp r Bx 4 z1hc compare A-r
|
|||
|
cp n FE nn 8 z1hc compare A-n
|
|||
|
cp (HL) BE 8 z1hc compare A-(HL)
|
|||
|
inc r xx 4 z0h- r=r+1
|
|||
|
inc (HL) 34 12 z0h- (HL)=(HL)+1
|
|||
|
dec r xx 4 z1h- r=r-1
|
|||
|
dec (HL) 35 12 z1h- (HL)=(HL)-1
|
|||
|
daa 27 4 z-0x decimal adjust akku
|
|||
|
cpl 2F 4 -11- A = A xor FF
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB 16bit-Arithmetic/logical Commands<br>
|
|||
|
</b><table><tbody><tr><td><pre> add HL,rr x9 8 -0hc HL = HL+rr ;rr may be BC,DE,HL,SP
|
|||
|
inc rr x3 8 ---- rr = rr+1 ;rr may be BC,DE,HL,SP
|
|||
|
dec rr xB 8 ---- rr = rr-1 ;rr may be BC,DE,HL,SP
|
|||
|
add SP,dd E8 16 00hc SP = SP +/- dd ;dd is 8bit signed number
|
|||
|
ld HL,SP+dd F8 12 00hc HL = SP +/- dd ;dd is 8bit signed number
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB Rotate- und Shift-Commands<br>
|
|||
|
</b><table><tbody><tr><td><pre> rlca 07 4 000c rotate akku left
|
|||
|
rla 17 4 000c rotate akku left through carry
|
|||
|
rrca 0F 4 000c rotate akku right
|
|||
|
rra 1F 4 000c rotate akku right through carry
|
|||
|
rlc r CB 0x 8 z00c rotate left
|
|||
|
rlc (HL) CB 06 16 z00c rotate left
|
|||
|
rl r CB 1x 8 z00c rotate left through carry
|
|||
|
rl (HL) CB 16 16 z00c rotate left through carry
|
|||
|
rrc r CB 0x 8 z00c rotate right
|
|||
|
rrc (HL) CB 0E 16 z00c rotate right
|
|||
|
rr r CB 1x 8 z00c rotate right through carry
|
|||
|
rr (HL) CB 1E 16 z00c rotate right through carry
|
|||
|
sla r CB 2x 8 z00c shift left arithmetic (b0=0)
|
|||
|
sla (HL) CB 26 16 z00c shift left arithmetic (b0=0)
|
|||
|
swap r CB 3x 8 z000 exchange low/hi-nibble
|
|||
|
swap (HL) CB 36 16 z000 exchange low/hi-nibble
|
|||
|
sra r CB 2x 8 z00c shift right arithmetic (b7=b7)
|
|||
|
sra (HL) CB 2E 16 z00c shift right arithmetic (b7=b7)
|
|||
|
srl r CB 3x 8 z00c shift right logical (b7=0)
|
|||
|
srl (HL) CB 3E 16 z00c shift right logical (b7=0)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB Singlebit Operation Commands<br>
|
|||
|
</b><table><tbody><tr><td><pre> bit n,r CB xx 8 z01- test bit n
|
|||
|
bit n,(HL) CB xx 12 z01- test bit n
|
|||
|
set n,r CB xx 8 ---- set bit n
|
|||
|
set n,(HL) CB xx 16 ---- set bit n
|
|||
|
res n,r CB xx 8 ---- reset bit n
|
|||
|
res n,(HL) CB xx 16 ---- reset bit n
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB CPU-Controlcommands<br>
|
|||
|
</b><table><tbody><tr><td><pre> ccf 3F 4 -00c cy=cy xor 1
|
|||
|
scf 37 4 -001 cy=1
|
|||
|
nop 00 4 ---- no operation
|
|||
|
halt 76 N*4 ---- halt until interrupt occurs (low power)
|
|||
|
stop 10 00 ? ---- low power standby mode (VERY low power)
|
|||
|
di F3 4 ---- disable interrupts, IME=0
|
|||
|
ei FB 4 ---- enable interrupts, IME=1
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>GMB Jumpcommands<br>
|
|||
|
</b><table><tbody><tr><td><pre> jp nn C3 nn nn 16 ---- jump to nn, PC=nn
|
|||
|
jp HL E9 4 ---- jump to HL, PC=HL
|
|||
|
jp f,nn xx nn nn 16;12 ---- conditional jump if nz,z,nc,c
|
|||
|
jr PC+dd 18 dd 12 ---- relative jump to nn (PC=PC+/-7bit)
|
|||
|
jr f,PC+dd xx dd 12;8 ---- conditional relative jump if nz,z,nc,c
|
|||
|
call nn CD nn nn 24 ---- call to nn, SP=SP-2, (SP)=PC, PC=nn
|
|||
|
call f,nn xx nn nn 24;12 ---- conditional call if nz,z,nc,c
|
|||
|
ret C9 16 ---- return, PC=(SP), SP=SP+2
|
|||
|
ret f xx 20;8 ---- conditional return if nz,z,nc,c
|
|||
|
reti D9 16 ---- return and enable interrupts (IME=1)
|
|||
|
rst n xx 16 ---- call to 00,08,10,18,20,28,30,38
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="cpucomparisionwithz80"></a><font size="+2"> CPU Comparision with Z80</font></td></tr></tbody></table><br>
|
|||
|
<b>Comparision with 8080<br>
|
|||
|
</b>Basically, the gameboy CPU works more like an older 8080 CPU rather than
|
|||
|
like a more powerful Z80 CPU. It is, however, supporting CB-prefixed
|
|||
|
instructions. Also, all known gameboy assemblers using the more obvious
|
|||
|
Z80-style syntax, rather than the chaotic 8080-style syntax.<br>
|
|||
|
<br>
|
|||
|
<b>Comparision with Z80<br>
|
|||
|
</b>Any DD-, ED-, and FD-prefixed instructions are missing, that means no
|
|||
|
IX-, IY-registers, no block commands, and some other missing commands.<br>
|
|||
|
All exchange instructions have been removed (including total absence of
|
|||
|
second register set), 16bit memory accesses are mostly missing, and
|
|||
|
16bit arithmetic functions are heavily cut-down.<br>
|
|||
|
The gameboy has no IN/OUT instructions, instead I/O ports are accessed
|
|||
|
directly by normal LD instructions, or by special LD (FF00+n) opcodes.<br>
|
|||
|
The sign and parity/overflow flags have been removed.<br>
|
|||
|
The gameboy operates approximately as fast as a 4MHz Z80 (8MHz in CGB
|
|||
|
double speed mode), execution time of all instructions has been rounded
|
|||
|
up to a multiple of 4 cycles though.<br>
|
|||
|
<br>
|
|||
|
<b>Moved, Removed, and Added Opcodes<br>
|
|||
|
</b><table><tbody><tr><td><pre> Opcode Z80 GMB
|
|||
|
---------------------------------------
|
|||
|
08 EX AF,AF LD (nn),SP
|
|||
|
10 DJNZ PC+dd STOP
|
|||
|
22 LD (nn),HL LDI (HL),A
|
|||
|
2A LD HL,(nn) LDI A,(HL)
|
|||
|
32 LD (nn),A LDD (HL),A
|
|||
|
3A LD A,(nn) LDD A,(HL)
|
|||
|
D3 OUT (n),A -
|
|||
|
D9 EXX RETI
|
|||
|
DB IN A,(n) -
|
|||
|
DD <IX> -
|
|||
|
E0 RET PO LD (FF00+n),A
|
|||
|
E2 JP PO,nn LD (FF00+C),A
|
|||
|
E3 EX (SP),HL -
|
|||
|
E4 CALL P0,nn -
|
|||
|
E8 RET PE ADD SP,dd
|
|||
|
EA JP PE,nn LD (nn),A
|
|||
|
EB EX DE,HL -
|
|||
|
EC CALL PE,nn -
|
|||
|
ED <pref> -
|
|||
|
F0 RET P LD A,(FF00+n)
|
|||
|
F2 JP P,nn LD A,(FF00+C)
|
|||
|
F4 CALL P,nn -
|
|||
|
F8 RET M LD HL,SP+dd
|
|||
|
FA JP M,nn LD A,(nn)
|
|||
|
FC CALL M,nn -
|
|||
|
FD <IY> -
|
|||
|
CB3X SLL r/(HL) SWAP r/(HL)
|
|||
|
</pre></td></tr></tbody></table>Note: The unused (-) opcodes will lock-up the gameboy CPU when used.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="thecartridgeheader"></a><font size="+2"> The Cartridge Header</font></td></tr></tbody></table><br>
|
|||
|
An internal information area is located at 0100-014F in<br>
|
|||
|
each cartridge. It contains the following values:<br>
|
|||
|
<br>
|
|||
|
<b>0100-0103 - Entry Point<br>
|
|||
|
</b>After displaying the Nintendo Logo, the built-in boot procedure jumps to
|
|||
|
this address (100h), which should then jump to the actual main program
|
|||
|
in the cartridge. Usually this 4 byte area contains a NOP instruction,
|
|||
|
followed by a JP 0150h instruction. But not always.<br>
|
|||
|
<br>
|
|||
|
<b>0104-0133 - Nintendo Logo<br>
|
|||
|
</b>These bytes define the bitmap of the Nintendo logo that is displayed
|
|||
|
when the gameboy gets turned on. The hexdump of this bitmap is:<br>
|
|||
|
<table><tbody><tr><td><pre> CE ED 66 66 CC 0D 00 0B 03 73 00 83 00 0C 00 0D
|
|||
|
00 08 11 1F 88 89 00 0E DC CC 6E E6 DD DD D9 99
|
|||
|
BB BB 67 63 6E 0E EC CC DD DC 99 9F BB B9 33 3E
|
|||
|
</pre></td></tr></tbody></table>The gameboys boot procedure verifies the content of this bitmap (after
|
|||
|
it has displayed it), and LOCKS ITSELF UP if these bytes are incorrect.
|
|||
|
A CGB verifies only the first 18h bytes of the bitmap, but others (for
|
|||
|
example a pocket gameboy) verify all 30h bytes.<br>
|
|||
|
<br>
|
|||
|
<b>0134-0143 - Title<br>
|
|||
|
</b>Title of the game in UPPER CASE ASCII. If it is less than 16 characters
|
|||
|
then the remaining bytes are filled with 00's. When inventing the CGB,
|
|||
|
Nintendo has reduced the length of this area to 15 characters, and some
|
|||
|
months later they had the fantastic idea to reduce it to 11 characters
|
|||
|
only. The new meaning of the ex-title bytes is described below.<br>
|
|||
|
<br>
|
|||
|
<b>013F-0142 - Manufacturer Code<br>
|
|||
|
</b>In older cartridges this area has been part of the Title (see above), in
|
|||
|
newer cartridges this area contains an 4 character uppercase
|
|||
|
manufacturer code. Purpose and Deeper Meaning unknown.<br>
|
|||
|
<br>
|
|||
|
<b>0143 - CGB Flag<br>
|
|||
|
</b>In older cartridges this byte has been part of the Title (see above). In
|
|||
|
CGB cartridges the upper bit is used to enable CGB functions. This is
|
|||
|
required, otherwise the CGB switches itself into Non-CGB-Mode. Typical
|
|||
|
values are:<br>
|
|||
|
<table><tbody><tr><td><pre> 80h - Game supports CGB functions, but works on old gameboys also.
|
|||
|
C0h - Game works on CGB only (physically the same as 80h).
|
|||
|
</pre></td></tr></tbody></table>Values with Bit 7 set, and either Bit 2 or 3 set, will switch the
|
|||
|
gameboy into a special non-CGB-mode with uninitialized palettes. Purpose
|
|||
|
unknown, eventually this has been supposed to be used to colorize
|
|||
|
monochrome games that include fixed palette data at a special location
|
|||
|
in ROM.<br>
|
|||
|
<br>
|
|||
|
<b>0144-0145 - New Licensee Code<br>
|
|||
|
</b>Specifies a two character ASCII licensee code, indicating the company or
|
|||
|
publisher of the game. These two bytes are used in newer games only
|
|||
|
(games that have been released after the SGB has been invented). Older
|
|||
|
games are using the header entry at 014B instead.<br>
|
|||
|
<br>
|
|||
|
<b>0146 - SGB Flag<br>
|
|||
|
</b>Specifies whether the game supports SGB functions, common values are:<br>
|
|||
|
<table><tbody><tr><td><pre> 00h = No SGB functions (Normal Gameboy or CGB only game)
|
|||
|
03h = Game supports SGB functions
|
|||
|
</pre></td></tr></tbody></table>The SGB disables its SGB functions if this byte is set to another value
|
|||
|
than 03h.<br>
|
|||
|
<br>
|
|||
|
<b>0147 - Cartridge Type<br>
|
|||
|
</b>Specifies which Memory Bank Controller (if any) is used in the
|
|||
|
cartridge, and if further external hardware exists in the cartridge.<br>
|
|||
|
<table><tbody><tr><td><pre> 00h ROM ONLY 13h MBC3+RAM+BATTERY
|
|||
|
01h MBC1 15h MBC4
|
|||
|
02h MBC1+RAM 16h MBC4+RAM
|
|||
|
03h MBC1+RAM+BATTERY 17h MBC4+RAM+BATTERY
|
|||
|
05h MBC2 19h MBC5
|
|||
|
06h MBC2+BATTERY 1Ah MBC5+RAM
|
|||
|
08h ROM+RAM 1Bh MBC5+RAM+BATTERY
|
|||
|
09h ROM+RAM+BATTERY 1Ch MBC5+RUMBLE
|
|||
|
0Bh MMM01 1Dh MBC5+RUMBLE+RAM
|
|||
|
0Ch MMM01+RAM 1Eh MBC5+RUMBLE+RAM+BATTERY
|
|||
|
0Dh MMM01+RAM+BATTERY FCh POCKET CAMERA
|
|||
|
0Fh MBC3+TIMER+BATTERY FDh BANDAI TAMA5
|
|||
|
10h MBC3+TIMER+RAM+BATTERY FEh HuC3
|
|||
|
11h MBC3 FFh HuC1+RAM+BATTERY
|
|||
|
12h MBC3+RAM
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>0148 - ROM Size<br>
|
|||
|
</b>Specifies the ROM Size of the cartridge. Typically calculated as "32KB
|
|||
|
shl N".<br>
|
|||
|
<table><tbody><tr><td><pre> 00h - 32KByte (no ROM banking)
|
|||
|
01h - 64KByte (4 banks)
|
|||
|
02h - 128KByte (8 banks)
|
|||
|
03h - 256KByte (16 banks)
|
|||
|
04h - 512KByte (32 banks)
|
|||
|
05h - 1MByte (64 banks) - only 63 banks used by MBC1
|
|||
|
06h - 2MByte (128 banks) - only 125 banks used by MBC1
|
|||
|
07h - 4MByte (256 banks)
|
|||
|
52h - 1.1MByte (72 banks)
|
|||
|
53h - 1.2MByte (80 banks)
|
|||
|
54h - 1.5MByte (96 banks)
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>0149 - RAM Size<br>
|
|||
|
</b>Specifies the size of the external RAM in the cartridge (if any).<br>
|
|||
|
<table><tbody><tr><td><pre> 00h - None
|
|||
|
01h - 2 KBytes
|
|||
|
02h - 8 Kbytes
|
|||
|
03h - 32 KBytes (4 banks of 8KBytes each)
|
|||
|
</pre></td></tr></tbody></table>When using a MBC2 chip 00h must be specified in this entry, even though
|
|||
|
the MBC2 includes a built-in RAM of 512 x 4 bits.<br>
|
|||
|
<br>
|
|||
|
<b>014A - Destination Code<br>
|
|||
|
</b>Specifies if this version of the game is supposed to be sold in japan,
|
|||
|
or anywhere else. Only two values are defined.<br>
|
|||
|
<table><tbody><tr><td><pre> 00h - Japanese
|
|||
|
01h - Non-Japanese
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>014B - Old Licensee Code<br>
|
|||
|
</b>Specifies the games company/publisher code in range 00-FFh. A value of
|
|||
|
33h signalizes that the New License Code in header bytes 0144-0145 is
|
|||
|
used instead.<br>
|
|||
|
(Super GameBoy functions won't work if <> $33.)<br>
|
|||
|
<br>
|
|||
|
<b>014C - Mask ROM Version number<br>
|
|||
|
</b>Specifies the version number of the game. That is usually 00h.<br>
|
|||
|
<br>
|
|||
|
<b>014D - Header Checksum<br>
|
|||
|
</b>Contains an 8 bit checksum across the cartridge header bytes 0134-014C.
|
|||
|
The checksum is calculated as follows:<br>
|
|||
|
<table><tbody><tr><td><pre> x=0:FOR i=0134h TO 014Ch:x=x-MEM[i]-1:NEXT
|
|||
|
</pre></td></tr></tbody></table>The lower 8 bits of the result must be the same than the value in this
|
|||
|
entry. The GAME WON'T WORK if this checksum is incorrect.<br>
|
|||
|
<br>
|
|||
|
<b>014E-014F - Global Checksum<br>
|
|||
|
</b>Contains a 16 bit checksum (upper byte first) across the whole cartridge
|
|||
|
ROM. Produced by adding all bytes of the cartridge (except for the two
|
|||
|
checksum bytes). The Gameboy doesn't verify this checksum.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="memorybankcontrollers"></a><font size="+2"> Memory Bank Controllers</font></td></tr></tbody></table><br>
|
|||
|
As the gameboys 16 bit address bus offers only limited space for ROM and
|
|||
|
RAM addressing, many games are using Memory Bank Controllers (MBCs) to
|
|||
|
expand the available address space by bank switching. These MBC chips
|
|||
|
are located in the game cartridge (ie. not in the gameboy itself),
|
|||
|
several different MBC types are available:<br>
|
|||
|
<br>
|
|||
|
<a href="#none32kbyteromonly">None (32KByte ROM only)</a><br>
|
|||
|
<a href="#mbc1max2mbyteromandor32kbyteram">MBC1 (max 2MByte ROM and/or 32KByte RAM)</a><br>
|
|||
|
<a href="#mbc2max256kbyteromand512x4bitsram">MBC2 (max 256KByte ROM and 512x4 bits RAM)</a><br>
|
|||
|
<a href="#mbc3max2mbyteromandor32kbyteramandtimer">MBC3 (max 2MByte ROM and/or 32KByte RAM and Timer)</a><br>
|
|||
|
<a href="#huc1mbcwithinfraredcontroller">HuC1 (MBC with Infrared Controller)</a><br>
|
|||
|
<br>
|
|||
|
<a href="#mbctimingissues">MBC Timing Issues</a><br>
|
|||
|
<br>
|
|||
|
In each cartridge, the required (or preferred) MBC type should be
|
|||
|
specified in byte at 0147h of the ROM. (As described in the chapter
|
|||
|
about The Cartridge Header.)<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="none32kbyteromonly"></a><font size="+2"> None (32KByte ROM only)</font></td></tr></tbody></table><br>
|
|||
|
Small games of not more than 32KBytes ROM do not require a MBC chip for
|
|||
|
ROM banking. The ROM is directly mapped to memory at 0000-7FFFh.
|
|||
|
Optionally up to 8KByte of RAM could be connected at A000-BFFF, even
|
|||
|
though that could require a tiny MBC-like circuit, but no real MBC chip.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="mbc1max2mbyteromandor32kbyteram"></a><font size="+2"> MBC1 (max 2MByte ROM and/or 32KByte RAM)</font></td></tr></tbody></table><br>
|
|||
|
This is the first MBC chip for the gameboy. Any newer MBC chips are
|
|||
|
working similiar, so that is relative easy to upgrade a program from one
|
|||
|
MBC chip to another - or even to make it compatible to several different
|
|||
|
types of MBCs.<br>
|
|||
|
<br>
|
|||
|
Note that the memory in range 0000-7FFF is used for both reading from
|
|||
|
ROM, and for writing to the MBCs Control Registers.<br>
|
|||
|
<br>
|
|||
|
<b>0000-3FFF - ROM Bank 00 (Read Only)<br>
|
|||
|
</b>This area always contains the first 16KBytes of the cartridge ROM.<br>
|
|||
|
<br>
|
|||
|
<b>4000-7FFF - ROM Bank 01-7F (Read Only)<br>
|
|||
|
</b>This area may contain any of the further 16KByte banks of the ROM,
|
|||
|
allowing to address up to 125 ROM Banks (almost 2MByte). As described
|
|||
|
below, bank numbers 20h, 40h, and 60h cannot be used, resulting in the
|
|||
|
odd amount of 125 banks.<br>
|
|||
|
<br>
|
|||
|
<b>A000-BFFF - RAM Bank 00-03, if any (Read/Write)<br>
|
|||
|
</b>This area is used to address external RAM in the cartridge (if any).
|
|||
|
External RAM is often battery buffered, allowing to store game positions
|
|||
|
or high score tables, even if the gameboy is turned off, or if the
|
|||
|
cartridge is removed from the gameboy. Available RAM sizes are: 2KByte
|
|||
|
(at A000-A7FF), 8KByte (at A000-BFFF), and 32KByte (in form of four 8K
|
|||
|
banks at A000-BFFF).<br>
|
|||
|
<br>
|
|||
|
<b>0000-1FFF - RAM Enable (Write Only)<br>
|
|||
|
</b>Before external RAM can be read or written, it must be enabled by
|
|||
|
writing to this address space. It is recommended to disable external RAM
|
|||
|
after accessing it, in order to protect its contents from damage during
|
|||
|
power down of the gameboy. Usually the following values are used:<br>
|
|||
|
<table><tbody><tr><td><pre> 00h Disable RAM (default)
|
|||
|
0Ah Enable RAM
|
|||
|
</pre></td></tr></tbody></table>Practically any value with 0Ah in the lower 4 bits enables RAM, and any
|
|||
|
other value disables RAM.<br>
|
|||
|
<br>
|
|||
|
<b>2000-3FFF - ROM Bank Number (Write Only)<br>
|
|||
|
</b>Writing to this address space selects the lower 5 bits of the ROM Bank
|
|||
|
Number (in range 01-1Fh). When 00h is written, the MBC translates that
|
|||
|
to bank 01h also. That doesn't harm so far, because ROM Bank 00h can be
|
|||
|
always directly accessed by reading from 0000-3FFF.<br>
|
|||
|
But (when using the register below to specify the upper ROM Bank bits),
|
|||
|
the same happens for Bank 20h, 40h, and 60h. Any attempt to address
|
|||
|
these ROM Banks will select Bank 21h, 41h, and 61h instead.<br>
|
|||
|
<br>
|
|||
|
<b>4000-5FFF - RAM Bank Number - or - Upper Bits of ROM Bank Number (Write Only)<brbr>
|
|||
|
</brbr></b>This 2bit register can be used to select a RAM Bank in range from
|
|||
|
00-03h, or to specify the upper two bits (Bit 5-6) of the ROM Bank
|
|||
|
number, depending on the current ROM/RAM Mode. (See below.)<br>
|
|||
|
<br>
|
|||
|
<b>6000-7FFF - ROM/RAM Mode Select (Write Only)<br>
|
|||
|
</b>This 1bit Register selects whether the two bits of the above register
|
|||
|
should be used as upper two bits of the ROM Bank, or as RAM Bank Number.<br>
|
|||
|
<table><tbody><tr><td><pre> 00h = ROM Banking Mode (up to 8KByte RAM, 2MByte ROM) (default)
|
|||
|
01h = RAM Banking Mode (up to 32KByte RAM, 512KByte ROM)
|
|||
|
</pre></td></tr></tbody></table>The program may freely switch between both modes, the only limitiation
|
|||
|
is that only RAM Bank 00h can be used during Mode 0, and only ROM Banks
|
|||
|
00-1Fh can be used during Mode 1.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="mbc2max256kbyteromand512x4bitsram"></a><font size="+2"> MBC2 (max 256KByte ROM and 512x4 bits RAM)</font></td></tr></tbody></table><br>
|
|||
|
<b>0000-3FFF - ROM Bank 00 (Read Only)<br>
|
|||
|
</b>Same as for MBC1.<br>
|
|||
|
<br>
|
|||
|
<b>4000-7FFF - ROM Bank 01-0F (Read Only)<br>
|
|||
|
</b>Same as for MBC1, but only a total of 16 ROM banks is supported.<br>
|
|||
|
<br>
|
|||
|
<b>A000-A1FF - 512x4bits RAM, built-in into the MBC2 chip (Read/Write)<br>
|
|||
|
</b>The MBC2 doesn't support external RAM, instead it includes 512x4 bits of
|
|||
|
built-in RAM (in the MBC2 chip itself). It still requires an external
|
|||
|
battery to save data during power-off though.<br>
|
|||
|
As the data consists of 4bit values, only the lower 4 bits of the
|
|||
|
"bytes" in this memory area are used.<br>
|
|||
|
<br>
|
|||
|
<b>0000-1FFF - RAM Enable (Write Only)<br>
|
|||
|
</b>The least significant bit of the upper address byte must be zero to
|
|||
|
enable/disable cart RAM. For example the following addresses can be used
|
|||
|
to enable/disable cart RAM: 0000-00FF, 0200-02FF, 0400-04FF, ...,
|
|||
|
1E00-1EFF.<br>
|
|||
|
The suggested address range to use for MBC2 ram enable/disable is
|
|||
|
0000-00FF.<br>
|
|||
|
<br>
|
|||
|
<b>2000-3FFF - ROM Bank Number (Write Only)<br>
|
|||
|
</b>Writing a value (XXXXBBBB - X = Don't cares, B = bank select bits) into
|
|||
|
2000-3FFF area will select an appropriate ROM bank at 4000-7FFF.<br>
|
|||
|
<br>
|
|||
|
The least significant bit of the upper address byte must be one to
|
|||
|
select a ROM bank. For example the following addresses can be used to
|
|||
|
select a ROM bank: 2100-21FF, 2300-23FF, 2500-25FF, ..., 3F00-3FFF.<br>
|
|||
|
The suggested address range to use for MBC2 rom bank selection is
|
|||
|
2100-21FF.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="mbc3max2mbyteromandor32kbyteramandtimer"></a><font size="+2"> MBC3 (max 2MByte ROM and/or 32KByte RAM and Timer)</font></td></tr></tbody></table><br>
|
|||
|
Beside for the ability to access up to 2MB ROM (128 banks), and 32KB RAM
|
|||
|
(4 banks), the MBC3 also includes a built-in Real Time Clock (RTC). The
|
|||
|
RTC requires an external 32.768 kHz Quartz Oscillator, and an external
|
|||
|
battery (if it should continue to tick when the gameboy is turned off).<br>
|
|||
|
<br>
|
|||
|
<b>0000-3FFF - ROM Bank 00 (Read Only)<br>
|
|||
|
</b>Same as for MBC1.<br>
|
|||
|
<br>
|
|||
|
<b>4000-7FFF - ROM Bank 01-7F (Read Only)<br>
|
|||
|
</b>Same as for MBC1, except that accessing banks 20h, 40h, and 60h is
|
|||
|
supported now.<br>
|
|||
|
<br>
|
|||
|
<b>A000-BFFF - RAM Bank 00-03, if any (Read/Write)<br>
|
|||
|
A000-BFFF - RTC Register 08-0C (Read/Write)<br>
|
|||
|
</b>Depending on the current Bank Number/RTC Register selection (see below),
|
|||
|
this memory space is used to access an 8KByte external RAM Bank, or a
|
|||
|
single RTC Register.<br>
|
|||
|
<br>
|
|||
|
<b>0000-1FFF - RAM and Timer Enable (Write Only)<br>
|
|||
|
</b>Mostly the same as for MBC1, a value of 0Ah will enable reading and
|
|||
|
writing to external RAM - and to the RTC Registers! A value of 00h will
|
|||
|
disable either.<br>
|
|||
|
<br>
|
|||
|
<b>2000-3FFF - ROM Bank Number (Write Only)<br>
|
|||
|
</b>Same as for MBC1, except that the whole 7 bits of the RAM Bank Number
|
|||
|
are written directly to this address. As for the MBC1, writing a value
|
|||
|
of 00h, will select Bank 01h instead. All other values 01-7Fh select the
|
|||
|
corresponding ROM Banks.<br>
|
|||
|
<br>
|
|||
|
<b>4000-5FFF - RAM Bank Number - or - RTC Register Select (Write Only)<br>
|
|||
|
</b>As for the MBC1s RAM Banking Mode, writing a value in range for 00h-03h
|
|||
|
maps the corresponding external RAM Bank (if any) into memory at
|
|||
|
A000-BFFF.<br>
|
|||
|
When writing a value of 08h-0Ch, this will map the corresponding RTC
|
|||
|
register into memory at A000-BFFF. That register could then be
|
|||
|
read/written by accessing any address in that area, typically that is
|
|||
|
done by using address A000.<br>
|
|||
|
<br>
|
|||
|
<b>6000-7FFF - Latch Clock Data (Write Only)<br>
|
|||
|
</b>When writing 00h, and then 01h to this register, the current time
|
|||
|
becomes latched into the RTC registers. The latched data will not change
|
|||
|
until it becomes latched again, by repeating the write 00h->01h
|
|||
|
procedure.<br>
|
|||
|
This is supposed for <reading> from the RTC registers. It is proof to
|
|||
|
read the latched (frozen) time from the RTC registers, while the clock
|
|||
|
itself continues to tick in background.<br>
|
|||
|
<br>
|
|||
|
<b>The Clock Counter Registers<br>
|
|||
|
</b><table><tbody><tr><td><pre> 08h RTC S Seconds 0-59 (0-3Bh)
|
|||
|
09h RTC M Minutes 0-59 (0-3Bh)
|
|||
|
0Ah RTC H Hours 0-23 (0-17h)
|
|||
|
0Bh RTC DL Lower 8 bits of Day Counter (0-FFh)
|
|||
|
0Ch RTC DH Upper 1 bit of Day Counter, Carry Bit, Halt Flag
|
|||
|
Bit 0 Most significant bit of Day Counter (Bit 8)
|
|||
|
Bit 6 Halt (0=Active, 1=Stop Timer)
|
|||
|
Bit 7 Day Counter Carry Bit (1=Counter Overflow)
|
|||
|
</pre></td></tr></tbody></table>The Halt Flag is supposed to be set before <writing> to the RTC
|
|||
|
Registers.<br>
|
|||
|
<br>
|
|||
|
<b>The Day Counter<br>
|
|||
|
</b>The total 9 bits of the Day Counter allow to count days in range from
|
|||
|
0-511 (0-1FFh). The Day Counter Carry Bit becomes set when this value
|
|||
|
overflows. In that case the Carry Bit remains set until the program does
|
|||
|
reset it.<br>
|
|||
|
Note that you can store an offset to the Day Counter in battery RAM. For
|
|||
|
example, every time you read a non-zero Day Counter, add this Counter to
|
|||
|
the offset in RAM, and reset the Counter to zero. This method allows to
|
|||
|
count any number of days, making your program Year-10000-Proof, provided
|
|||
|
that the cartridge gets used at least every 511 days.<br>
|
|||
|
<br>
|
|||
|
<b>Delays<br>
|
|||
|
</b>When accessing the RTC Registers it is recommended to execute a 4ms
|
|||
|
delay (4 Cycles in Normal Speed Mode) between the separate accesses.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="huc1mbcwithinfraredcontroller"></a><font size="+2"> HuC1 (MBC with Infrared Controller)</font></td></tr></tbody></table><br>
|
|||
|
This controller (made by Hudson Soft) appears to be very similar to an
|
|||
|
MBC1 with the main difference being that it supports infrared LED input
|
|||
|
/ output. (Similiar to the infrared port that has been later invented in
|
|||
|
CGBs.)<br>
|
|||
|
<br>
|
|||
|
The Japanese cart "Fighting Phoenix" (internal cart name: SUPER B DAMAN)
|
|||
|
is known to contain this chip.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="mbctimingissues"></a><font size="+2"> MBC Timing Issues</font></td></tr></tbody></table><br>
|
|||
|
<b>Using MBCs with CGB Double Speed Mode<br>
|
|||
|
</b>The MBC5 has been designed to support CGB Double Speed Mode.<br>
|
|||
|
There have been rumours that older MBCs (like MBC1-3) wouldn't be fast
|
|||
|
enough in that mode. If so, it might be nethertheless possible to use
|
|||
|
Double Speed during periods which use only code and data which is
|
|||
|
located in internal RAM.<br>
|
|||
|
However, despite of the above, my own good old selfmade MBC1-EPROM card
|
|||
|
appears to work stable and fine even in Double Speed Mode though.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="gamegeniesharkcheats"></a><font size="+2"> Gamegenie/Shark Cheats</font></td></tr></tbody></table><br>
|
|||
|
Game Shark and Gamegenie are external cartridge adapters that can be
|
|||
|
plugged between the gameboy and the actual game cartridge. Hexadecimal
|
|||
|
codes can be then entered for specific games, typically providing things
|
|||
|
like Infinite Sex, 255 Cigarettes, or Starting directly in Wonderland
|
|||
|
Level PRO, etc.<br>
|
|||
|
<br>
|
|||
|
<b>Gamegenie (ROM patches)<br>
|
|||
|
</b>Gamegenie codes consist of nine-digit hex numbers, formatted as
|
|||
|
ABC-DEF-GHI, the meaning of the separate digits is:<br>
|
|||
|
<table><tbody><tr><td><pre> AB New data
|
|||
|
FCDE Memory address, XORed by 0F000h
|
|||
|
GI Old data, XORed by 0BAh and rotated left by two
|
|||
|
H Don't know, maybe checksum and/or else
|
|||
|
</pre></td></tr></tbody></table>The address should be located in ROM area 0000h-7FFFh, the adapter
|
|||
|
permanently compares address/old data with address/data being read by
|
|||
|
the game, and replaces that data by new data if necessary. That method
|
|||
|
(more or less) prohibits unwanted patching of wrong memory banks.
|
|||
|
Eventually it is also possible to patch external RAM ?<br>
|
|||
|
Newer devices reportedly allow to specify only the first six digits
|
|||
|
(optionally). As far as I rememeber, around three or four codes can be
|
|||
|
used simultaneously.<br>
|
|||
|
<br>
|
|||
|
<b>Game Shark (RAM patches)<br>
|
|||
|
</b>Game Shark codes consist of eight-digit hex numbers, formatted as
|
|||
|
ABCDEFGH, the meaning of the separate digits is:<br>
|
|||
|
<table><tbody><tr><td><pre> AB External RAM bank number
|
|||
|
CD New Data
|
|||
|
GHEF Memory Address (internal or external RAM, A000-DFFF)
|
|||
|
</pre></td></tr></tbody></table>As far as I understand, patching is implement by hooking the original
|
|||
|
VBlank interrupt handler, and re-writing RAM values each frame. The
|
|||
|
downside is that this method steals some CPU time, also, it cannot be
|
|||
|
used to patch program code in ROM.<br>
|
|||
|
As far as I rememeber, somewhat 10-25 codes can be used simultaneously.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="powerupsequence"></a><font size="+2"> Power Up Sequence</font></td></tr></tbody></table><br>
|
|||
|
When the GameBoy is powered up, a 256 byte program starting at memory
|
|||
|
location 0 is executed. This program is located in a ROM inside the
|
|||
|
GameBoy. The first thing the program does is read the cartridge
|
|||
|
locations from $104 to $133 and place this graphic of a Nintendo logo on
|
|||
|
the screen at the top. This image is then scrolled until it is in the
|
|||
|
middle of the screen. Two musical notes are then played on the internal
|
|||
|
speaker. Again, the cartridge locations $104 to $133 are read but this
|
|||
|
time they are compared with a table in the internal rom. If any byte
|
|||
|
fails to compare, then the GameBoy stops comparing bytes and simply
|
|||
|
halts all operations. If all locations compare the same, then the
|
|||
|
GameBoy starts adding all of the bytes in the cartridge from $134 to
|
|||
|
$14d. A value of 25 decimal is added to this total. If the least
|
|||
|
significant byte of the result is a not a zero, then the GameBoy will
|
|||
|
stop doing anything. If it is a zero, then the internal ROM is disabled
|
|||
|
and cartridge program execution begins at location $100 with the
|
|||
|
following register values:<br>
|
|||
|
<br>
|
|||
|
<table><tbody><tr><td><pre> AF=$01B0
|
|||
|
BC=$0013
|
|||
|
DE=$00D8
|
|||
|
HL=$014D
|
|||
|
Stack Pointer=$FFFE
|
|||
|
[$FF05] = $00 ; TIMA
|
|||
|
[$FF06] = $00 ; TMA
|
|||
|
[$FF07] = $00 ; TAC
|
|||
|
[$FF10] = $80 ; NR10
|
|||
|
[$FF11] = $BF ; NR11
|
|||
|
[$FF12] = $F3 ; NR12
|
|||
|
[$FF14] = $BF ; NR14
|
|||
|
[$FF16] = $3F ; NR21
|
|||
|
[$FF17] = $00 ; NR22
|
|||
|
[$FF19] = $BF ; NR24
|
|||
|
[$FF1A] = $7F ; NR30
|
|||
|
[$FF1B] = $FF ; NR31
|
|||
|
[$FF1C] = $9F ; NR32
|
|||
|
[$FF1E] = $BF ; NR33
|
|||
|
[$FF20] = $FF ; NR41
|
|||
|
[$FF21] = $00 ; NR42
|
|||
|
[$FF22] = $00 ; NR43
|
|||
|
[$FF23] = $BF ; NR30
|
|||
|
[$FF24] = $77 ; NR50
|
|||
|
[$FF25] = $F3 ; NR51
|
|||
|
[$FF26] = $F1-GB, $F0-SGB ; NR52
|
|||
|
[$FF40] = $91 ; LCDC
|
|||
|
[$FF42] = $00 ; SCY
|
|||
|
[$FF43] = $00 ; SCX
|
|||
|
[$FF45] = $00 ; LYC
|
|||
|
[$FF47] = $FC ; BGP
|
|||
|
[$FF48] = $FF ; OBP0
|
|||
|
[$FF49] = $FF ; OBP1
|
|||
|
[$FF4A] = $00 ; WY
|
|||
|
[$FF4B] = $00 ; WX
|
|||
|
[$FFFF] = $00 ; IE
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
It is not a good idea to assume the above values will always exist. A
|
|||
|
later version GameBoy could contain different values than these at
|
|||
|
reset. Always set these registers on reset rather than assume they are
|
|||
|
as above.<br>
|
|||
|
<br>
|
|||
|
Please note that GameBoy internal RAM on power up contains random data.
|
|||
|
All of the GameBoy emulators tend to set all RAM to value $00 on entry.<br>
|
|||
|
<br>
|
|||
|
Cart RAM the first time it is accessed on a real GameBoy contains random
|
|||
|
data. It will only contain known data if the GameBoy code initializes it
|
|||
|
to some value.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="reducingpowerconsumption"></a><font size="+2"> Reducing Power Consumption</font></td></tr></tbody></table><br>
|
|||
|
The following can be used to recude the power consumption of the
|
|||
|
gameboy, and to extend the life of the batteries.<br>
|
|||
|
<br>
|
|||
|
<a href="#pwrusingthehaltinstruction">PWR Using the HALT Instruction</a><br>
|
|||
|
<a href="#pwrusingthestopinstruction">PWR Using the STOP Instruction</a><br>
|
|||
|
<a href="#pwrdisabelingthesoundcontroller">PWR Disabeling the Sound Controller</a><br>
|
|||
|
<a href="#pwrnotusingcgbdoublespeedmode">PWR Not using CGB Double Speed Mode</a><br>
|
|||
|
<a href="#pwrusingtheskills">PWR Using the Skills</a><br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="pwrusingthehaltinstruction"></a><font size="+2"> PWR Using the HALT Instruction</font></td></tr></tbody></table><br>
|
|||
|
It is recommended that the HALT instruction be used whenever possible to
|
|||
|
reduce power consumption & extend the life of the batteries. This
|
|||
|
command stops the system clock reducing the power consumption of both
|
|||
|
the CPU and ROM.<br>
|
|||
|
<br>
|
|||
|
The CPU will remain suspended until an interrupt occurs at which point
|
|||
|
the interrupt is serviced and then the instruction immediately following
|
|||
|
the HALT is executed.<br>
|
|||
|
<br>
|
|||
|
Depending on how much CPU time is required by a game, the HALT
|
|||
|
instruction can extend battery life anywhere from 5 to 50% or possibly
|
|||
|
more.<br>
|
|||
|
<br>
|
|||
|
When waiting for a vblank event, this would be a BAD example:<br>
|
|||
|
<table><tbody><tr><td><pre> @@wait:
|
|||
|
ld a,(0FF44h) ;LY
|
|||
|
cp a,144
|
|||
|
jr nz,@@wait
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
A better example would be a procedure as shown below. In this case the
|
|||
|
vblank interrupt must be enabled, and your vblank interrupt procedure
|
|||
|
must set vblank_flag to a non-zero value.<br>
|
|||
|
<table><tbody><tr><td><pre> ld hl,vblank_flag ;hl=pointer to vblank_flag
|
|||
|
xor a ;a=0
|
|||
|
@@wait: ;wait...
|
|||
|
halt ;suspend CPU - wait for ANY interrupt
|
|||
|
cp a,(hl) ;vblank flag still zero?
|
|||
|
jr z,@@wait ;wait more if zero
|
|||
|
ld (hl),a ;set vblank_flag back to zero
|
|||
|
</pre></td></tr></tbody></table>The vblank_flag is used to determine whether the HALT period has been
|
|||
|
terminated by a vblank interrupt, or by another interrupt. In case that
|
|||
|
your program has all other interrupts disabled, then it would be proof
|
|||
|
to replace the above procedure by a single HALT instruction.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="pwrusingthestopinstruction"></a><font size="+2"> PWR Using the STOP Instruction</font></td></tr></tbody></table><br>
|
|||
|
The STOP instruction is intended to switch the gameboy into VERY low
|
|||
|
power standby mode. For example, a program may use this feature when it
|
|||
|
hasn't sensed keyboard input for a longer period (assuming that somebody
|
|||
|
forgot to turn off the gameboy).<br>
|
|||
|
<br>
|
|||
|
Before invoking STOP, it might be required to disable Sound and Video
|
|||
|
manually (as well as IR-link port in CGB). Much like HALT, the STOP
|
|||
|
state is terminated by interrupt events - in this case this would be
|
|||
|
commonly a joypad interrupt. The joypad register might be required to be
|
|||
|
prepared for STOP either.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="pwrdisabelingthesoundcontroller"></a><font size="+2"> PWR Disabeling the Sound Controller</font></td></tr></tbody></table><br>
|
|||
|
If your programs doesn't use sound at all (or during some periods) then
|
|||
|
write 00h to register FF26 to save 16% or more on GB power consumption.<br>
|
|||
|
Sound can be turned back on by writing 80h to the same register, all
|
|||
|
sound registers must be then re-initialized.<br>
|
|||
|
When the gameboy becomes turned on, sound is enabled by default, and
|
|||
|
must be turned off manually when not used.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="pwrnotusingcgbdoublespeedmode"></a><font size="+2"> PWR Not using CGB Double Speed Mode</font></td></tr></tbody></table><br>
|
|||
|
Because CGB Double Speed mode consumes more power, it'd be recommended
|
|||
|
to use normal speed when possible.<br>
|
|||
|
There's limited ability to switch between both speeds, for example, a
|
|||
|
game might use normal speed in the title screen, and double speed in the
|
|||
|
game, or vice versa.<br>
|
|||
|
However, during speed switch the display collapses for a short moment,
|
|||
|
so that it'd be no good idea to alter speeds within active game or title
|
|||
|
screen periods.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="pwrusingtheskills"></a><font size="+2"> PWR Using the Skills</font></td></tr></tbody></table><br>
|
|||
|
Most of the above power saving methods will produce best results when
|
|||
|
using efficient and tight assembler code which requires as less CPU
|
|||
|
power as possible. Thus, experienced old-school programmers will
|
|||
|
(hopefully) produce lower power consumption, as than HLL-programming
|
|||
|
teenagers, for example.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="spriterambug"></a><font size="+2"> Sprite RAM Bug</font></td></tr></tbody></table><br>
|
|||
|
There is a flaw in the GameBoy hardware that causes trash to be written
|
|||
|
to OAM RAM if the following commands are used while their 16-bit content
|
|||
|
is in the range of $FE00 to $FEFF:<br>
|
|||
|
<table><tbody><tr><td><pre> inc rr dec rr ;rr = bc,de, or hl
|
|||
|
ldi a,(hl) ldd a,(hl)
|
|||
|
ldi (hl),a ldd (hl),a
|
|||
|
</pre></td></tr></tbody></table>Only sprites 1 & 2 ($FE00 & $FE04) are not affected by these
|
|||
|
instructions.<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="externalconnectors"></a><font size="+2"> External Connectors</font></td></tr></tbody></table><br>
|
|||
|
<b>Cartridge Slot<br>
|
|||
|
</b><table><tbody><tr><td><pre> Pin Name Expl.
|
|||
|
1 VDD Power Supply +5V DC
|
|||
|
2 PHI System Clock
|
|||
|
3 /WR Write
|
|||
|
4 /RD Read
|
|||
|
5 /CS Chip Select
|
|||
|
6-21 A0-A15 Address Lines
|
|||
|
22-29 D0-D7 Data Lines
|
|||
|
30 /RES Reset signal
|
|||
|
31 VIN External Sound Input
|
|||
|
32 GND Ground
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>Link Port<br>
|
|||
|
</b>Pin numbers are arranged as 2,4,6 in upper row, 1,3,5 un lower row;
|
|||
|
outside view of gameboy socket; flat side of socket upside.<br>
|
|||
|
Colors as used in most or all standard link cables, because SIN and SOUT
|
|||
|
are crossed, colors Red and Orange are exchanged at one cable end.<br>
|
|||
|
<table><tbody><tr><td><pre> Pin Name Color Expl.
|
|||
|
1 VCC - +5V DC
|
|||
|
2 SOUT red Data Out
|
|||
|
3 SIN orange Data In
|
|||
|
4 P14 - Not used
|
|||
|
5 SCK green Shift Clock
|
|||
|
6 GND blue Ground
|
|||
|
</pre></td></tr></tbody></table>Note: The original gameboy used larger plugs (unlike pocket gameboys and
|
|||
|
newer), linking between older/newer gameboys is possible by using cables
|
|||
|
with one large and one small plug though.<br>
|
|||
|
<br>
|
|||
|
<b>Stereo Sound Connector (3.5mm, female)<br>
|
|||
|
</b><table><tbody><tr><td><pre> Pin Expl.
|
|||
|
Tip Sound Left
|
|||
|
Middle Sound Right
|
|||
|
Base Ground
|
|||
|
</pre></td></tr></tbody></table><br>
|
|||
|
<b>External Power Supply<br>
|
|||
|
</b>...<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<br>
|
|||
|
<table width="100%"><tbody><tr bgcolor="#cccccc"><td><a name="end"></a><font size="+2"> END</font></td></tr></tbody></table>
|
|||
|
</body></html>
|