Game Boy
Transcrição
Game Boy
Contents Part I Hardware 1 1 Overview 1.1 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Schematics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 The Processor 2.1 Architecture . . . . . . . . . . . . 2.2 Addressing modes . . . . . . . . . 2.3 Registers . . . . . . . . . . . . . . 2.4 Instruction set . . . . . . . . . . . 2.4.1 Notation . . . . . . . . . . 2.4.2 Comparison with the Z80 2.4.3 Overview . . . . . . . . . 3 3 3 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 7 7 8 9 9 10 Memory map and cartridge memory 3.1 Memory areas . . . . . . . . . . . . . . . . . . . . . . 3.2 Internal control of the memory area* . . . . . . . . . 3.3 Cartridge memory . . . . . . . . . . . . . . . . . . . . 3.3.1 ROM-only cartridge . . . . . . . . . . . . . . 3.3.2 Extending the cartridge memory . . . . . . . 3.3.3 MBC1 . . . . . . . . . . . . . . . . . . . . . . 3.3.4 MBC2 . . . . . . . . . . . . . . . . . . . . . . 3.3.5 MBC3 . . . . . . . . . . . . . . . . . . . . . . 3.3.6 MBC5 . . . . . . . . . . . . . . . . . . . . . . 3.4 Internal functions of the memory bank controllers* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 15 17 18 18 20 21 21 21 21 21 4 The video system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 i Contents 5 The sound system 25 6 The joypad 27 7 Der Timer 29 8 The serial port 31 9 Interrupts 33 Part II 35 Software 10 Der Game Boy Assembler 10.1 Installation . . . . . . . . . 10.2 Syntax . . . . . . . . . . . . 10.2.1 Labels . . . . . . . 10.2.2 Kommentare . . . 10.2.3 Befehle . . . . . . . 10.2.4 Spezielle Symbole 10.3 Projekte erstellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 37 37 38 38 38 39 39 11 Projekt: Goodbye World! 43 12 Project: playing music 45 Part III Projekte 47 13 Cartridge Programmer 49 14 Function generator 51 ii Contents Part IV Anhänge 53 A Befehlssatz A.1 Alphabetisch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Opcodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 55 55 B Special Function Register 59 B.1 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 B.2 Detailed description . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 C Code Schnipsel C.1 Bedingungen . . . . . . . . . . . . . . . . . A=B . . . . . . . . . . . . . . . . . . . . . A≠B . . . . . . . . . . . . . . . . . . . . . A<B . . . . . . . . . . . . . . . . . . . . . A>B . . . . . . . . . . . . . . . . . . . . . A≤B . . . . . . . . . . . . . . . . . . . . . A≥B . . . . . . . . . . . . . . . . . . . . . . BC ≠ 0 . . . . . . . . . . . . . . . . . . . . . C.2 Schleifen . . . . . . . . . . . . . . . . . . . Schleife mit 256 ($100) Durchgängen . . Schleife mit n8 ×256 ($100) Durchgängen Schleife mit n16 Durchgängen . . . . . . . C.3 Read the joypad . . . . . . . . . . . . . . . C.4 Optimized alternatives . . . . . . . . . . . Clear the accumulator . . . . . . . . . . . . Vergleiche A mit $00 . . . . . . . . . . . . Vertauschen von DE und HL . . . . . . . . HL mit 16-Bit-Wert aus Adresse laden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 71 71 72 72 73 74 74 74 75 75 75 76 76 77 77 77 78 78 D Tabellen 79 D.1 Tonwiedergabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 E The boot ROMs* 81 iii PART I HARDWARE 1 Chapter 1 Overview Figure 1.1: The Game Boy Classic as found in US-Patent No. 5,095,798. 1.1 History 1.2 Schematics The hardware of the Game Boy is split into several separated printed circuit boards (PCBs): main board, LCD, DC/DC-converter, etc. For understanding the functionality of the Game Boy the main board is the most important component, including CPU, RAMs, Keys (the so-called joypad), a serial port and the audio circuit. The complete schematic of the Game Boy is shown in figures 1.2 and 1.3 with CPU U1 beeing the heart of the Game Boy1 . The CPU is clocked by an external Quartz Q1 with a frequency of 4.194304 MHz. This number sounds pretty arbitrary but exactly equals 222 Hz; very comfortable for timing applications. Both the Video RAM (V-RAM) U2 and the internal RAM (S-RAM) U3 were placed external from the CPU. These RAMs are controlled by separate data and 1 The schematics are split in a logical way and not necessarily like the separated PCBs. 3 Chapter 1 Overview address lines. It has to be possible that the V-RAM can be read independently of the S-RAM for the display. Note that the control lines of the S-RAM (CS, RD und WR) are the same as the control lines used for the cartridge (CON1 ). In order to control any of the internal and external memory in a nonambiguous way, the current memory address has to be considered. That is, memory mapped addressing is essential for the operation of the Game Boy. See chapter 3 for details of the Game Boy’s memory map. To the right of the schematic there is the 32-pin cartridge connector CON1 where the game cartridges are plugged in. The internals of the cartridge are discussed in section 3.3, pp. 18. Beside data, address and control lines also reset and clock signals are conducted from the CPU to the cartridge. In the opposite direction an analog audio signal (AIN – analog in) can be fed into the CPU-internal audio processor. This additional signal will also be interesting for up-loading of data into home-made cartridges, see therefore chapter 13. For accessing the peripherals, the Game Boy CPU possesses further lines. The joypad is read out by a special port P10 –P15 , see figured 1.3a and chapter 6. The circuit for the serial port (pins SOUT, SIN, SCX and surprisingly P14 ) is shown in figure 1.3b (and explained in chapter 8), for the audio circuit see figure 1.3c (and chapter ?? for details). The lines that are used to control the LCD are directly connected to the LCD board. A comprehensive introduction to the video system is found in chapter 4. 4 1.2 Schematics C1 73 b b +5 V b D0 D1 D2 D3 D4 D5 D6 D7 1 n. c. 26 CS2 28 VCC 14 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 OE WR CS1 GND V-RAM 8k × 8 LCD Joypad 10 9 8 7 6 5 4 3 25 24 21 23 2 Bus MA0..12 Bus MD0..7 11 12 13 15 16 17 18 19 X0 Q1 C2 U2 U1 74 X1 33 31 30 29 28 27 26 25 MD0 MD1 MD2 MD3 MD4 MD5 MD6 MD7 34 35 36 37 38 39 40 41 48 47 44 46 42 MA0 MA1 MA2 MA3 MA4 MA5 MA6 MA7 MA8 MA9 MA10 MA11 MA12 45 49 43 22 27 20 D1 D0 Ctrl Clock HSync DLCH AltSig VSync P10 P11 P12 P13 P14 P15 +5 V 50 51 52 53 54 55 56 57 67 66 65 64 63 62 58 MOE MWR MCS LD1 LD0 CPG CP ST CPL FR S P10 P11 P12 P13 P14 P15 VDD A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 D0 D1 D2 D3 D4 D5 D6 D7 17 18 19 20 21 22 23 24 WR RD CS RST CLK AIN CON1 +5 V Bus A0..15 Bus D0..7 U3 11 12 13 15 16 17 18 19 78 wr 79 rd 80 cs 71 rst 75 clk wr 27 rd 22 cs 20 1 14 61 ain D0 D1 D2 D3 D4 D5 D6 D7 WR OE CS1 n. c. GND A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 10 9 8 7 6 5 4 3 25 24 21 23 2 CS2 26 VCC 28 S-RAM 8k × 8 Control Bus AOUTL AOUTR 60 59 SOUT SIN SCX 70 69 68 T1 T2 77 76 VSS1 32 VSS2 72 AOutL AOutR Audio SOut SIn SCx Serial a14 +5 V 1 VCC 32 GND 22 23 24 25 26 27 28 29 D0 D1 D2 D3 D4 D5 D6 D7 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 wr 3 rd 4 cs 5 rst 30 clk 2 ain 31 WR RD CS RST CLK AIN Cart b b b CPU Figure 1.2: Schematic of the CPU part. 5 Chapter 1 Overview b → DA2 .A b ← DA1 .A 1 A DA3 .A P10 1 1 P11 2 2 B DA4 .A ↑ DA1 .B 1 3 b 2 b 2 b Select DA3 .B b b ↓ 3 2 b DA2 .B 3 2 b Start DA4 .B 3 2 DA1 –DA4 . . . DAN215 b P14 P15 P12 P13 2 (a) Joypad. (b) Serial port. (c) Au-(d) Power dio supcir- ply. cuit. Figure 1.3: Schematics of the peripherals: joypad (a), serial port (b), audio circuit (c) and power supply. 6 Chapter 2 The Processor This chapter provides an overview of the CPU. In particular, its core is introduced. The CPU en bloc (U1 ) also contains functions like the audio system etc. but are covered in upcoming chapters. Processor is used here as synonym for the CPU’s core. 2.1 Architecture 2.2 Addressing modes 2.3 Registers The registers of a processor provide the most straightforward data processing. Most processor instructions directly act on that registers. The Game Boy processor contains following registers: ◾ accumulator A (8 bits) and flag register F(8 bits, 4 bits used) ◾ program counter PC(16 bits) ◾ general purpose registers B, C, D, E, H and L(8 bits, can be combined to 16 bits) ◾ stack pointer SP(16 bits) The accumulator plays an important role since a lot of instructions use the accumulator as operand and/or as register for the result. Depending on the result distinct bits of the flag register are set or reset. The flag register contains four different flags that are arranged in the high nibble (bits 7–4): ◾ F.7 C Z Zero flag. Z = 1, if the last result has been 0. 7 Chapter 2 The Processor ◾ F.6 C N Add/Substract flag. N = 1, if the last instructions has been an subtraction. ◾ F.5 C H Halfcarry flag. H = 1, if there occured an overflow from low nibble (that is, from bit 3 into bit 4) in the last instruction. ◾ F.4 C C Carry flag. C = 1, if there occured a (normal) overflow in the last instruction. The low nibble (F.3–F.0) of the flag register is unused. Some flags have different meanings for distinct instructions, for example when two numbers are compared. A more detailed explanation is given in the list of instructions (appendix A). The program counter contains the address of the address where the next instructions is to be executed. Since the address bus is 16 bits wide, the PC has to have 16 bits, too. In order to temporarily store further data general purpose registers are provided. Each two of that 8 bit registers can be combined to form a 16 bit register, namely BC, DE and HL. For both the 8 bit and 16 bit there are separate instructions available. When a subroutine is called or and interrupt is triggered, the program has to have the possibility to find back to the calling routine when the subroutine/interrupt is finished. The Game Boy (like most microcontrollers) uses the stack to store the last address of the calling routine to fulfill that task. The 16 bit stack pointer register points to the address of the last entry of the stack. The programmer has to carefully select an internal RAM area of appropriate size that is not overlapping with other data. 2.4 Instruction set In diesem Abschnitt wird eine Übersicht über den Befehlsumfang des Prozessors gegeben. Unterschiedlich sortierte Auflistungen aller Befehle finden sich im Anhang A ab Seite 55. 8 2.4 Instruction set 2.4.1 Notation Für Befehle, die für den Game-Boy-Prozessor vom Z80 übernommen wurden, wird die Z80-Notation verwendet. Für Befehle, die es beim Z80 nicht gibt, wird die Notation des RGBDS-Assembler (siehe Teil II) verwendet. Dieser Notation folgend werden bei der indirekten Adressierung daher auch anstelle der runden Klammern eckige Klammern verwendet. Hexadezimale Zahlen werden durch ein $-Zeichen als Präfix von dezimalen Zahlen (kein Präfix) unterschieden. 8-Bitund 16-Bit-Konstanten ohne Vorzeichen werden mittels n8 (s8 mit Vorzeichen) bzw. n16 dargestellt, 8-Bit- und 16-Bit-Register mittels r8 bzw. r16 . Bei bitweisen Befehlen wird das b3 als Bitstelle (0 bis 7) verwendet. 2.4.2 Comparison with the Z80 Leser, die bereits vertraut mit der Programmierung des Z80 sind, können die anschließende Befehlsübersicht überspringen. Für solche ist es ausreichend, sich der Unterschiede gegenüber dem Z80 bewusst zu sein. Gleich eine ganze Reihe von Registern wurden für den Game-Boy-Prozessor entfernt. Dies sind alle Spiegelregister (A’, F’, B’, C’, D’, E’, H’ und L’), alle Interrupt-Register (I, IFF1 , IFF2 , IMFA und IMFB ), das DRAM-Refreshregister R und die Index-Register IX und IY. Dem Flagregister wurden das VorzeichenFlag S (Sign) und das Parity-/Overflow-Flag P/V entfernt. Die verbleibenden vier Flags wurden allesamt im High Nibble angesiedelt (siehe oben). Alle Befehle, die mit diesen Registern beziehungsweise Flags in Verbindung stehen, sind folgendlich nicht implementiert. Eine weitere Besonderheit des Game-Boy-Prozessors ist, das keine externen Ports zur Verfügung stehen. Damit erübrigen sich auch sämtliche IN- und OUTBefehle. Wie aber werden Kontakte zur Außenwelt (Cartridge, Display, etc.) hergestellt? Dies geschieht beim Game Boy allein durch Lesen und Schreiben von bzw. an bestimmten Adressen, also Memory mapped. Die verschiedenen Speicherbereiche werden gesondert im nächsten Kapitel erläutert. Ebenfalls entfernt wurden die Exchange-Befehle (EX), also Befehle zum Vertauschen von Inhalten. Allerdings sind auch eine Reihe neuer Befehle hinzugekommen, nämlich (Opcode in Klammern): ◾ ADD SP,s8 ($E8) 9 Chapter 2 The Processor ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ LD HL,SP+s8 ($F8) LD SP,n16 ($31) LDI A,[HL] ($2A) LDI [HL],A ($22) LDD A,[HL] ($3A) LDD [HL],A ($32) LD A,[$FF00+n8 ] ($F0) LD A,[$FF00+C] ($F2) LD [$FF00+n8 ],A ($E0) LD [$FF00+C],A ($E2) STOP ($10) SWAP r8 ($CB $30 bis $CB $35 und $CB $37) SWAP [HL] ($CB $36) Weiters haben drei Befehle einen geänderten Opcode (Z80 → Game Boy): ◾ LD A,[n16 ] ($3A → $FA) ◾ LD [n16 ],A ($32 → $EA) ◾ RETI ($ED $4D → $D9) 2.4.3 Overview An dieser Stelle wird ein kurzer Überblick der Befehle gegeben, um eine gewisse Vorstellung der Möglichkeiten des Game-Boy-Prozessors zu erhalten: was kann eine Zeile Assemblercode alles mit den Daten anstellen? Loading instructions Ladebefehle sind Befehle, mit deren Hilfe 8- oder 16-Bit-Daten von einem Ort zum nächsten kopiert werden. Diese Orte können entweder Register (direkte Adressierung) oder Adressen (indirekte Adressierung) sein, als Quelle können zusätzlich Kontanten bzw. konstante Adressen dienen. Achtung: das Ziel ist der linke Operand, die Quelle der rechte! Beispiele: ld ld ld 10 a,b ; wert von 8−bit−register b nach a kopieren hl,$1234 ; 16−bit−register hl mit wert $1234 laden a,[hl] ; wert von daten an der stelle $1234 nach a kopieren 2.4 Instruction set Im Gambe-Boy-Prozessor sind zusätzlich Ladebefehle implementiert, bei denen das Register HLbei indirekter Adressierung nach dem Laden in- bzw. dekrementiert wird. Die Stack-Pointer-Befehle PUSH und POP können zu den Ladebefehlen gezählt werden. Die Funktion des Stack Pointers wurde bereits in Abschnitt 2.3 behandelt. Arithmetic and logic instructions Unter Arithmetik fallen die Addition, Subtraktion, das Inkrementieren und Dekrementieren. Bei Addition (ADD) und Subtraktion (SUB) steht zusätzlich eine Variante zur Verfügung, die das Carry-Flag berücksichtigt: add adc sub sbc a,[hl] a,[hl] a,b a,d ; ; ; ; a a a a <− <− <− <− a a a a + + − − [hl] [hl] + C b d− C Es gibt auch noch den der Subtraktion ähnlichen Befehl CP (compare), der einen bestimmten Wert vom Akkumulator subtrahiert, aber nur zum Vergleichen dient. Der Akkumulator selbst wird dabei nicht geändert. Addition und Subtraktion ist nur mit 8-Bit-Daten möglich, In-/Dekrementieren hingegen auch für 16-Bit-Registern möglich, z. B. INC DE. An Logikbefehlen stehen AND, OR, XOR und das Einerkomplement (Inversion) CPL zur Verfügung. Da sich sämtliche Arithmetik- und Logikbefehle auf den Akkumulator beziehen, kann auch die Kurzschreibweise ohne Zieloperand verwendet werden, z. B. SUB B anstelle von SUB A,B. Für die Lesbarkeit des Codes sollte aber stets die lange Variante verwendet werden. Tipp: Häufig kommt es vor, dass man den Akkumulator mit Wert 0 initialisieren möchte. Anstelle des Befehls LD A,$00 kann die in der Ausführung schnellere Variante XOR A,A verwendet werden. Shift and rotation instructions Unter Shift versteht man das Verschieben aller Bits eines Register/einer Speicherstelle um eine Stelle nach links oder rechts. Das Bit, das dabei hinausgeschoben 11 Chapter 2 The Processor wird (Bit 7 bei Linksshift, Bit 0 bei Rechtsshift), landet im Carry. Das neu hineingeschobene Bit ist, je nach Befehl, entweder 0 (SLA und SRL) oder das MSB selbst (SRA). Bei Rotationsbefehlen dreht sich alles im Kreis. Bits, die auf einer Seite hinausgeschoben werden, kommen auf der anderen Seite wieder zurück. Das jeweils aktuell hinausgedrängte Bit befindet sich anschließend auch im Carry. Es kann entweder direkt rotiert werden (RLC und RRC; C für circular) oder ein Umweg über das Carry genommen werden (9-Bit-Rotation; RL und RR). Die SWAP-Befehle kann man auch zu den Rotationsbefehlen zählen. Dabei wird allerdings gleich viermal rotiert, sodass High- und Low-Nibble vertauscht sind. Instructions affecting single bits Von sämtlichen Registern kann jedes Bit einzeln gesetzt (SET b3 ,r8 bzw. SET b3 ,[HL]), gelöscht (RES b3 ,r8 bzw. RES b3 ,[HL]) oder geprüft (BIT b3 ,r8 bzw. BIT b3 ,[HL]) werden. Letzteres modifiziert das Z-Flag dementsprechend. Daneben gibt es noch Befehle speziell für das C-Flag: SCF (set carry flag) und CCF (complementary carry flag). Achtung: es gibt keinen direkten Befehl zum löschen des C-Flags! Jumping instructions Sprungbefehle ermöglichen das Verlassen der sequentiellen Abarbeitung des Programmcodes, indem das PC-Register manipuliert wird. Dadurch erst werden Strukturen wie if-Bedingungen oder for-Schleifen ermöglicht. Die einfachste Variante sind Sprünge zu bestimmten absoluten Adressen ohne Bedingung, z. B. JP n16 oder JP [HL] (A←HL). Zum Sparen von Speicherplatz und Ausführungszeit gibt es auch noch einen Sprung relativ zum aktuellen PC, nämlich JR s8 . Achtung: relative Sprünge dürfen als Adresse nur Labels benutzen, weil die absolute Adresse erst vom Assembler festgelegt werden kann. Sämtliche Sprungbefehle gibt es auch noch mit Bedingungen. Dazu wird der Zustand der Flags C/NC und Z/Z verwendet, beispielsweise JP NC,n16 . Zum Benutzen von Unterprogrammen sind die Befehle CALL und RET vorgesehen. Die Befehle CALL und RET gibt es ebenfalls mit und ohne Bedingungen. Bevor mittels CALL gesprungen wird, wird zuerst noch der aktuelle Wert des PC in den Stack abgelegt. Beim Verlassen des Unterprogramms mit RET wird der PC 12 2.4 Instruction set wieder dem Stack entnommen, sodass an der ursprünglichen Programmposition fortgesetzt werden kann. RETI wird lediglich zum Beenden von Interrupts benutzt. Interrupts werden im Detail in Kapitel 9 behandelt. Ähnlich dem CALL-Befehl funktionieren die RST n8 Befehle. Der PC wird auf den Stack abgelegt und anschließend mit der fixen Adresse $0000+n8 geladen. Als Werte für n8 sind nur erlaubt: $00, $08, $10, $18, $20, $28, $30 und $38. Further instructions Zur Erleichterung von Rechnungen mit zwei BCD-Zahlen (0–9 anstelle von 0– F) kann das Rechenergebnis einer Addition bzw. Subtraktion mit Hilfe von DAA (decimal adjust accumulator) korrigiert werden. Dieser Befehl verwendet intern die beiden Flags Nund H, die sonst von außen nicht zugänglich sind. Zum Ein- und Ausschalten der gesamten Interrupts werden die Befehle EI und DI benötigt. Der spezielle Befehle STOP beendet die Ausführung des Programms, bis ein beliebige Taste am Game Boy gedrückt wird. HALT stoppt die Ausführung des Programms, bis ein Interrupt ausgelöst wird. Mehr dazu siehe Kapitel 9. Schließlich gibt es noch den einfachsten aller Befehle, nämlich NOP – no operation. Dieser Befehl macht einen Maschinenzyklus lange überhaupt nichts. Er ist für Timing-Aufgaben sinnvoll. 13 Chapter 3 Memory map and cartridge memory 3.1 Memory areas It has already been mentioned in the introduction that the Game Boy does not possess direct inputs and outputs to communicate with the outside world (see also the schematic in figure 1.2). All the data exchange has to be accomplished memory mapped. Memory mapped means, that the current address is used to access distinct peripherals. Depending on the address different chip select, read and write signals of the peripherals are controlled. There are 16 address and 8 data lines available at the Game Boy. That is, 64 KBit times 8 Bit (64 KByte) can be directly address (addresses 0 up to &1111 1111 1111 1111). In hexadecimal notation the address space reaches from $0000 to $FFFF. This address space has been split up to allow the access to internal and external memorys. External in this context is the memory outside the Game Boy, that is, the cartridge memory. The allocation of the memory areas is summarized in table 3.1. The entire first half of the address space is reserved for the external ROM. The external ROM contains the entire game (program) including data for graphics, sound, etc.1 The simplest cartridge is just equipped with a single 32-KByte ROM2 (for example games like Tetris or Super Mario). Such cartridges can directly be read from $0000–$7FFF. If that amount of mermory is not sufficient there is the possibility to switch between entire ROM areas (so called banks) with an additional chip inside the cartridge. Details about different cartridge configurations can be found in section 3.3 below. The area $8000–$9FFF is used for the Video RAM (V-RAM), that holds data 1 The Game Boy is therefore an example for the classic Von-Neumann architecture. This in op- posite to the NES, that has at least separated program and graphics ROM on the cartridge. 2 One compares this amount of memory with an empty Word-2003 file, having approximately 23 KByte. 15 Chapter 3 Memory map and cartridge memory Area Size in bytes $0000–$3FFF $4000–$7FFF $8000–$9FFF $A000–$BFFF $C000–$DFFF $E000–$FDFF $FE00–$FE9F $FEA0–$FEFF $FF00–$FF4B $FF4C–$FF7F $FF80–$FFFE $FFFF 16 k 16 k 8k 8k 8k 7 680 160 96 76 52 127 1 Purpose External ROM, bank 0 External ROM, bank n Video RAM External RAM (optional) Internal RAM (low RAM) Unused3 Sprite Attribute RAM (OAM) Unused Special Function Register (SFR) Unused4 Internal RAM (high RAM) Interrupt enable register Table 3.1: Memory map of the Game Boy Classic. for the LCD. The exact sub-areas of the V-RAM are explained in the following chapter. Some cartridges come with an external RAM (that is, games that allow to save user data like Super Mario 2). This RAM is addressed from $A000–$BFFF. It is appropriate that the external RAMs have a back-up battery to prevent amnesia. In comparison the internal RAM in area $C000–$DFFF is losing its contents when the Game Boy is switched off. The ensuing area $E000–$FDFF is just of theoretical interest; it is simply a mirror of the interal RAM from $C000–$DDFF. The sprite attribute RAM, also known as OAM, contains additional data for the display and is also covered in the following chapter. The following area from $FEA0–$FEFF is empty. In order to control Game Boy specific functions (joypad data, sound set-up, etc.) the area from $FF00–$FF4B is reserved. Address $FF00, for example, is used to read out joypad data. That is, addressing this area influences the behavior of special functions that are behind those registers. Some people call these registers I/O registers. According to the nomenclature of many micro-controllers we will use the designation special functions registers (SFRs) througout this book. Each of these special function registers are explained successively within the text; a complete list of all special function registers can be found in appendix B (pp. 59). 16 3.2 Internal control of the memory area* The area following the SFR area ($FF4C–$FF7F) is empty and unused in the case of a Game Boy Classic5 . However, the Game Boy Color uses part of that area for additional functions (color palettes, etc.). In general, "‘unused"’ areas should not be accessed because you never know what is hidden in future devices! Finally, there is an additional small RAM with 127 bytes (not 128 bytes!) in the area $FF80–$FFFE. This RAM is often used as Stack. The last accessable byte in the whole memory ($FFFF) can be added to the set of special function registers and is used to switch on/off different kinds of interrupts. 3.2 Internal control of the memory area* Für das Programmieren am Game Boy ist die Kenntnis der genauen Weise, wie der Game Boy nun zwischen den verschiedenen Adressbereichen unterscheidet, egal. Möchte jemand trotzdem über den Tellerrand hinaus schauen, so lassen sich diesbezüglich einige Überlegungen anstellen.6 Beginnen wir unsere Überlegungen zunächst, indem wir die hexadezimale Notation der Bereich in binäre umwandeln. Verwenden wir die einfachste Cartridge mit 32 kByte ROM (andere Varianten sind ähnlich und werden im kommenden Abschnitt erwähnt), so wird auf deren ROM im Bereich von &0000 0000 0000 0000 bis &0111 1111 1111 1111 zugegriffen. Man sieht, dass herbei die Adressleitungen A14 –A0 entweder 0 oder 1 sein können, es sich also um ein beliebiges Bit handelt. Schreibt man für ein beliebiges Bit nun ein X, so liegt das externe ROM in &0XXX XXXX XXXX XXXX. Die einzige Bedingung, damit auf das externe ROM zugegriffen werden kann, ist also nur, dass die Adressleitung A15 gleich 0 ist. In der Cartridge kann also diese Adressleitung für den (überlichterweise low-aktiven) Chip-Select-Eingang des ROMs verwendet werden. Das interne Video RAM (&100X XXXX XXXX XXXX) wird über gesonderte Adressund Datenleitungen bedient. Die Bedingung für das Chip-Select (CPU-Pin MCS) muss hier also lauten: MCS = A15 ⋅ A14 ⋅ A13 . 5 That’s not 100 % true since the Game Boy’s boot-ROM uses an undocumented register to switch itself off, see appendix ??. 6 Dazu muss man wissen, dass in den 80er Jahren noch nicht so sehr Transistoren verschwendet werden konnten, weil teuer. Jede notwendige Logik im Prozessor ist also möglichst einfach gehalten. 17 Chapter 3 Memory map and cartridge memory Laut Schaltplan (Abbildung 1.2) müssen sich das nun im Adressbereich folgende externe und interne RAM die Chip-Select-Leitung teilen. Um hier Überschneidungen mit dem SFR zu vermeiden, gibt der Prozessor ein Chip-Select (CPU-Pin CS) nur für einen Schreib-/Leseversuch an Adressen $A000–$FDFF ausprüfe das! schreibversuch an alle adressen und beobachtung der cs-leitung!. Innerhalb dieses Bereiches wird das externe RAM ansprechbar, wenn die Adressleitung A14 gleich 0 ist. Für das interne RAM muss die Adressleitung A14 dementsprechend 1 sein. Das sieht man auch im Schaltplan, da der CS2 -Eingang des internen RAMs direkt mit A14 verbunden ist. Da das interne RAM zumindest teilweise gespiegelt im Bereich $E000–$FDFF erscheint, liegt nahe, dass die Chip-Select-Leitung von der CPU folgendermaßen gesteuert wird: CS = A15 ⋅ MCS ⋅ A14 + A13 + A12 + A11 + A10 + A9 . Vermutet kann auch werden, dass alle Bytes ab $FE00 Teil eines einzigen RAMs sind. Manche Bytes können vom Prozessor auch gelesen und verändert werden (eine Art Dual-Port-RAM). 3.3 Cartridge memory In accordance to the schematic in figure 1.2 on page 5 the pins of the cartridge connector are summarized in table 3.2 (a cartrigde drawing with dimensions can be found in appendix ?? on page ??). Pins 1 and 32 are used to supply the cartridge with power. Pin 2 (Clock) can be used for special timing functions on the cartridge but is not wired on standard cartridges. Pins 3 to 5 are used to control the data flow of the cartridge’s memories, pins 6–21 are the address lines and pins 22–29 the data lines of the memories. On pin 30 there is the Game Boy’s reset line available. Pin 31 is an analog audio input (actually an output from the cartridges view) that is directly fed into the Game Boy’s sound system. This pin is not used on standard cartridges and is interesting for home-brewn programmers like the one shown in chapter 13 (pp. 49). 3.3.1 ROM-only cartridge If 32 kBytes of ROM are sufficient for storing both program and data memory, the address lines A0 to A14 can directly be connected to a ROM with 32 × 8 kbits (like 18 3.3 Cartridge memory Pin no. Name Description 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 VCC CLK WR RD CS A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 D0 D1 D2 D3 D4 D5 D6 D7 RST AIN GND Cartridge power supply +5 V Clock RAM write ROM/RAM read RAM chip select Address 0 Address 1 Address 2 Address 3 Address 4 Address 5 Address 6 Address 7 Address 8 Address 9 Address 10 Address 11 Address 12 Address 13 Address 14 Address 15 Data 0 Data 1 Data 2 Data 3 Data 4 Data 5 Data 6 Data 7 Reset Analog audio Cartridge ground Table 3.2: Cartridge pins. 19 Chapter 3 Memory map and cartridge memory the 27C256 ROM, 28C256 EEPROM or 28F256 Flash EEPROM). In that case it has to be prevented that the ROM is read when an address higher than $7FFF is to be accessed. One way to achieve this is to connect address line A15 directly to the (active low) chip enable/select (CE or CS) pin of the ROM, see figure 3.1. The contents of the ROM can now be read from $0000 to $3FFF and from $4000 to $7FFF. CON1 VCC 1 GND 32 D0 D1 D2 D3 D4 D5 D6 D7 22 23 24 25 26 27 28 29 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 WR RD CS RST CLK AIN 3 4 5 30 2 31 +5 V Bus D0..7 10 9 8 7 6 5 4 3 25 24 21 23 2 26 27 27 22 n. c. n. c. n. c. n. c. n. c. U1 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 CE OE D0 D1 D2 D3 D4 D5 D6 D7 11 12 13 15 16 17 18 19 VCC VPP 28 1 GND 14 +5 V b b C 100 n b 27C256P 8 k × 8 ROM Cart Figure 3.1: ROM-only cartridge configuration. 3.3.2 Extending the cartridge memory If the memory of the ROM-only cartridge are not sufficient a way has to be found to read a ROM with more than 32 kBytes but with still the same memory area 20 3.4 Internal functions of the memory bank controllers* from $0000 to $7FFF. A solution to bypass this bottle neck is following recipe: 1. Use a ROM with memory that is a multiple of 16 kBytes (n ⋅ 16 kBytes). 2. Directly connect address lines A0 to A13 of the cartridge connector to the ROM. 3. Somehow control the remaining higher address lines (A14 to A14 + ⌈log2 n⌉ ). This will divide the whole ROM into n banks of 16 kBytes. 4. Make the lowest bank (bank 0) always accessible in the area $0000–$3FFF. This will ensure that the execution (and the interrupts) always start(s) in bank 0. 5. Make banks 1–n accessible in the area $4000–$7FFF. The task to control the higher address lines and to map the banks is fulfilled by a special cartridge chip called memory bank controller (MBC). This MBCs can be controlled by the Game Boy by using the trick to write to locations where the ROM is located. Since either the read (RD) or the write ((WR)) signals are used, the ROM will not be affected when writing data to the area $0000–$7FFF. There are different types of MBCs that were used in Game Boy games. Some of the commonly used ones will be described now. 3.3.3 MBC1 3.3.4 MBC2 3.3.5 MBC3 3.3.6 MBC5 3.4 Internal functions of the memory bank controllers* 21 Chapter 4 The video system 23 Chapter 5 The sound system 25 Chapter 6 The joypad 27 Chapter 7 Der Timer 29 Chapter 8 The serial port 31 Chapter 9 Interrupts 33 PART II SOFTWARE 35 Chapter 10 Der Game Boy Assembler In diesem Kapitel wird die Verwendung eines Assemblers zur Programmierung des Game Boy kurz umrissen. Verwendet wird dabei der leistungsfähigste kostenlos verfügbare RGBASM (Rednex Game Boy Assembler). 10.1 Installation Der RGBASM besteht aus grundsätzlich vier Dateien: rgbasm.exe, xlink.exe, rgbfix.exe und xlib.exe. Diese findet man kostenlos im Internet1 . Am besten legt man ein neues Verzeichnis (z. B. C:\RGBASM) an und kopiert diese Dateien dort hinein. Fügt man das Verzeichnis noch der path-Variable hinzu, dann ist sowieso schon alles perfekt! 10.2 Syntax Die Befehle des Game-Boy-Prozessors, die in Kapitel 2 erläutert wurden, entsprechen bereits der Notation des RBGASM und können direkt im Programmcode verwendet werden. Diese Befehle allein machen es jedoch schwer, ein strukturiertes Programm zu schreiben. Deshalb steht der Assembler mit zusätzlichen Schlüsselwörtern zur Seite. Die Assemblerprogramme werden normalerweise in Textdateien mit der Endung *.asm angelegt. Jede Zeile des Programms folgt der Syntax Label, Befehl und Kommentar, wobei diese drei Teile jeweils optional sind. 1 http://www.otakunozoku.com/rednex-gameboy-development-system am 04.09.2011) (abgerufen 37 Chapter 10 Der Game Boy Assembler 10.2.1 Labels Labels dienen dazu, einer bestimmten Position (also Adresse) im Programm einen Namen zu geben, sodass der Programmierer auf diese Position verweisen kann, ohne die Position numerisch zu notieren. Die exakte Adresse eines Labels wird erst vom Linker festgelegt, deshalb haben Labels keine konstante Adresse. RGBASM unterscheidet zwischen globalen und lokalen Labels. Globale Labels sind beliebige Zeichenketten, die in der gesamten Datei gültig sind. Lokale Labels beginnen mit einem Punkt (.) und sind nur innerhalb globaler Labels gültig. Soll nach einem Label in der gleichen Zeile noch ein Befehl stehen, so muss an die Labelbezeichnung ein Doppelpunkt (:) angehängt werden. Globale Labels mit zwei Doppelpunkten werden gleichzeitig für den Export freigegeben (siehe unten). Beispiel: Globales_Label NochEinGlobalesLabel: .lokalesLabel NeuesGlobalesLabel: .lokalesLabel: LabelFuerExport:: Listing 10.1: Unterschiedliche Labels. Bei Labels wird zwischen Groß- und Kleinschreibung unterschieden. Zwecks übersichtlichkeit ist es bequen, globale Labels mit Groß- und lokale Labels mit Kleinbuchstaben zu beginnen. 10.2.2 Kommentare Wie bei anderen Assemblern auch beginnt ein Kommentar jeweils mit einem Semikolon (;) und endet mit Zeilenende. 10.2.3 Befehle An dieser Stelle sollen nur Befehle erwähnt werden, für die die Syntax etwas unklar sein könnte, weil in der Literatur verschiedene Notationen verwendet werden. Das betrifft die neuen Befehle des Gambe-Boys (siehe Abschnitt 2.4.2). Der RGBASM kennt drei Varianten für den Befehl LDI [HL],A, die äquivalent sind: 38 10.3 Projekte erstellen ldi ld ld [hl],a [hli],a [hl+],a Analog gestaltet sich der Befehl LDD A,[HL]. Besondere Vorsicht ist jedoch bei den Befehlen mit Adress-Offset [$FF00] geboten. Man vergleiche folgende Zeilen: con1 equ $40 con2 equ $ff40 ; ... ld a,[$ff00+$40] ld a,[$ff00+con1] ld a,[$40] ld a,[con1] ld a,[$ff40] ld a,[con2] ld a,[$ff00+c] ld a,[c] ; con1/2 festlegen ; ; ; ; ; ; ; ; ok ok −> ld a,[$0040] −> ld a,[$0040] ok ok ok ok Listing 10.2: .]Verhalten bei Adressierung im Bereich [$FF00]. 10.2.4 Spezielle Symbole section, equ, . . . 10.3 Projekte erstellen Ein neues Projekt wird folgendermaßen erzeugt: 1. 2. 3. 4. Neuen Ordner für das Projekt anlegen main.asm aus der Vorlage erstellen (siehe unten) Weitere asm-Dateien anlegen, hier als Beispiel somestuff.asm Linker-Datei mit z. B. Namen link.l anlegen mit Inhalt: [Objects] object/main.o object/somestuff.o 39 Chapter 10 Der Game Boy Assembler [Output] project.gb 5. Batch-Datei make.bat anlegen mit Inhalt: rgbasm -oobject/main.o main.asm rgbasm -oobject/somestuff.o somestuff.asm xlink -ts link.l rgbfix -ttitle -v project.gb 6. Unterordner object anlegen Für jede weitere Assembler-Datei fügt man die entsprechende Zeile in der LinkerDatei bzw. in der Batch-Datei hinzu. Als Vorlage für die main-Datei kann folgender Code verwendet werden: ; file: main.asm ; date: xx.xx.xxxx ; includes ; constant definitions ; equates ; header section "Org $00",HOME[$00] Rst00: jp $100 section "Org $08",HOME[$08] Rst08: jp $100 section "Org $10",HOME[$10] Rst10: jp $100 section "Org $18",HOME[$18] Rst18: jp $100 section "Org $20",HOME[$20] Rst20: jp $100 section "Org $28",HOME[$28] 40 10.3 Projekte erstellen Rst28: jp $100 section "Org $30",HOME[$30] Rst30: jp $100 section "Org $38",HOME[$38] Rst38: jp $100 section "V−Blank interrupt",HOME[$40] VBlankIR: reti section "LCD interrupt",HOME[$48] LcdIR: reti section "Timer interrupt",HOME[$50] TimerIR: reti section "Serial interrupt",HOME[$58] SerialIR: reti section "Joypad interrupt",HOME[$60] JoypadIR: reti ; game boy starts here section "Start",HOME[$0100] nop jp Main ; $0104−$0133 (Nintendo logo) db $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D db $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 db $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E db "",0,0 ; $0134−$013E (Game title) db " " ; $013F−$0142 (Product code) db $00 ; $0143 (Color GameBoy compatibility code) db $00 ; $0144 (License code) db $00 ; $0145 (License code) db $00 ; $0146 (GameBoy/Super GameBoy indicator) 41 Chapter 10 Der Game Boy Assembler db db db db db db db dw $00 $00 $00 $01 $33 $00 $00 $00 ; ; ; ; ; $0147 $0148 $0149 $014A $33 − (Cartridge type) (ROM size) (RAM size) (Destination code) Check $0144/$0145 for Licensee code. ; $014D (Complement check − handled by RGBFIX) ; $014E−$014F (Cartridge checksum − handled by RGBFIX) ; main program starts here! section "Main",HOME[$0150] Main: .endless: jr .endless ;~) eof Listing 10.3: main.asm-Vorlage Das Projekt wird nun mit make.bat erstellt. Als Ausgabe steht dann eine Datei mit Namen project.gb zur Verfügung. Diese Datei kann man nun vorerst im Emulator testen und anschließend in eine Cartridge programmieren. 42 Chapter 11 Projekt: Goodbye World! Als melancholisches Pendant zum schon etwas in die Jahre gekommenen "‘Hello World!"’ wollen wir mit unserem ersten Projekt versuchen, den Text "‘Goodbye World!"’ aufs Display zu zaubern. 43 Chapter 12 Project: playing music Nachdem im Kapitel 5 auf den Sound-Prozessor des Game Boys eingegangen wurde, wollen wir nun in einem kleinen Projekt versuchen, diesen Sound-Prozessor zur Wiedergabe von Musik zu benutzen. Zunächst soll eine einstimmige Melodie abgespielt werden. Danach erweitern wir das Projekt zur Wiedergabe von zweistimmigen Melodien. Zusätzlich werden wir dann versuchen, noch eine Rhythmusbegleitung abzuspielen. 45 PART III PROJEKTE 47 Chapter 13 Cartridge Programmer 49 Chapter 14 Function generator 51 PART IV ANHÄNGE 53 Appendix A Befehlssatz A.1 Alphabetisch ADD A,A A.2 Opcodes In den folgenden Tabellen sind die Befehle nach Opcodes sortiert. Vertikal ist das High Nibble angeordnet, horizontal das Low Nibble. 55 Appendix A Befehlssatz $_0 LD $_1 LD [BC],A $_2 INC BC $_3 INC B $_4 DEC B $_5 $_6 LD $_7 LD $_8 ADD HL,BC $_9 LD A,[BC] $_A DEC BC $_B INC C $_C DEC C $_D $_E LD $_F LD [DE],A INC SP INC HL INC DE LD D,H LD B,H INC [HL] LD [HL],L LD H,L LD D,L LD B,L DEC [HL] DEC H DEC D ADD A,[HL] HALT LD H,[HL] LD D,[HL] LD B,[HL] LD [HL],n8 LD H,n8 LD D,n8 AND A SUB A,A ADD A,A LD [HL],A LD H,A LD D,A LD B,A SCF DAA XOR B SBC A,B ADC A,B LD A,B LD L,B LD E,B LD C,B JR C,s8 JR Z,s8 JR s8 XOR C SBC A,C ADC A,C LD A,C LD L,C LD E,C LD C,C ADD HL,SP ADD HL,HL ADD HL,DE XOR D SBC A,D ADC A,D LD A,D LD L,D LD E,D LD C,D LDD A,[HL] LDI A,[HL] LD A,[DE] XOR E SBC A,E ADC A,E LD A,E LD L,E LD E,E LD C,E DEC SP DEC HL DEC DE XOR H SBC A,H ADC A,H LD A,H LD L,H LD E,H LD C,H INC A XOR L SBC A,L ADC A,L LD A,L LD L,L LD E,L LD C,L DEC A DEC L DEC E SBC A,[HL] ADC A,[HL] LD A,[HL] LD L,[HL] LD E,[HL] LD C,[HL] LD A,n8 LD L,n8 LD E,n8 SBC A,A ADC A,A LD A,A LD L,A LD E,A LD C,A CCF CPL RRA RRCA LDI [HL],A LD B,E LD H,H ADD A,L SUB A,[HL] RLCA LD DE,n16 LDD [HL],A LD D,E LD [HL],H SUB A,L NOP LD HL,n16 LD B,D LD D,E ADD A,H AND L $0_ STOP LD SP,n16 LD D,D LD [HL],E SUB A,H C,n8 JR NZ,s8 LD B,C LD H,D ADD A,E AND H INC E $2_ JR NC,s8 LD D,C LD [HL],D SUB A,E [n16 ],SP $3_ LD B,B LD H,C ADD A,D AND E XOR A RLA $4_ LD D,B LD [HL],C SUB A,D B,n8 $5_ LD H,B ADD A,C AND D INC D $6_ LD [HL],B SUB A,C BC,n16 $7_ ADD A,B AND C $1_ $8_ SUB A,B CP A INC L $9_ AND B XOR [HL] CP [HL] INC H $A_ AND [HL] CP L Z,n16 JP CP D CP H CP C CP E CP B RST $08 ADD OR A ADC RST $18 OR [HL] CALL A,n8 OR L CALL n16 SBC A,n8 RST $28 OR H Z,n16 - XOR n8 OR E $CBa Codes CALL C,n16 - RST $38 OR D - - CP n8 OR C JP C,n16 - - OR B RETI LD [n16 ],A - $B_ RET C JP [HL] EI RET A,n8 RST $10 ADD SP,s8 LD A,[n16 ] RET Z SUB n8 RST $20 LD LD HL,SP+s8 SP,HL RST $00 NZ,n16 PUSH DE AND n8 RST $30 PUSH BC n16 CALL NC,n16 PUSH HL OR n8 CALL - - PUSH AF JP JP NC,n16 - - JP POP DE LD [C],A1 DI POP BC RET NC POP HL LD A,[C]1 RET NZ $D_ LD [n8 ],Ab POP AF $C_ $E_ LD A,[n8 ]1 NZ,n16 $F_ Table A.1: 1-Byte-Opcodes des Game Boy-Prozessors. a $CB ist das erste Byte von den 2-Byte-Opcodes. Siehe nächste Tabelle. b Mit [n8 ] bzw. [C] wird an der Stelle [$FF00 + n8 ] bzw. [$FF00 + C] adressiert. Für die Verwendung im Assembler siehe Beispiel. 56 $_1 RLC C RL C SLA C SWAP C BIT 0,C BIT 2,C BIT 4,C BIT 6,C RES 0,C RES 2,C RES 4,C RES 6,C SET 0,C SET 2,C SET 4,C SET 6,C $_0 RLC B RL B SLA B SWAP B BIT 0,B BIT 2,B BIT 4,B BIT 6,B RES 0,B RES 2,B RES 4,B RES 6,B SET 0,B SET 2,B SET 4,B SET 6,B $CB $0_ $1_ $2_ $3_ $4_ $5_ $6_ $7_ $8_ $9_ $A_ $B_ $C_ $D_ $E_ $F_ SET 6,E SET 4,E SET 2,E SET 0,E RES 6,E RES 4,E RES 2,E RES 0,E BIT 6,E BIT 4,E BIT 2,E BIT 0,E SWAP E SLA E RL E RLC E $_3 SET 6,H SET 4,H SET 2,H SET 0,H RES 6,H RES 4,H RES 2,H RES 0,H BIT 6,H BIT 4,H BIT 2,H BIT 0,H SWAP H SLA H RL H RLC H $_4 SET 6,L SET 4,L SET 2,L SET 0,L RES 6,L RES 4,L RES 2,L RES 0,L BIT 6,L BIT 4,L BIT 2,L BIT 0,L SWAP L SLA L RL L RLC L $_5 RL A SLA A RL [HL] SLA [HL] SET 6,[HL] SET 4,[HL] SET 2,[HL] SET 0,[HL] RES 6,[HL] RES 4,[HL] RES 2,[HL] RES 0,[HL] BIT 6,[HL] BIT 4,[HL] BIT 2,[HL] BIT 0,[HL] SET 6,A SET 4,A SET 2,A SET 0,A RES 6,A RES 4,A RES 2,A RES 0,A BIT 6,A BIT 4,A BIT 2,A BIT 0,A SWAP A RLC A RLC [HL] SWAP [HL] $_7 $_6 SET 7,B SET 5,B SET 3,B SET 1,B RES 7,B RES 5,B RES 3,B RES 1,B BIT 7,B BIT 5,B BIT 3,B BIT 1,B SRL B SRA B RR B RRC B $_8 SET 7,C SET 5,C SET 3,C SET 1,C RES 7,C RES 5,C RES 3,C RES 1,C BIT 7,C BIT 5,C BIT 3,C BIT 1,C SRL C SRA C RR C RRC C $_9 SET 7,D SET 5,D SET 3,D SET 1,D RES 7,D RES 5,D RES 3,D RES 1,D BIT 7,D BIT 5,D BIT 3,D BIT 1,D SRL D SRA D RR D RRC D $_A SET 7,E SET 5,E SET 3,E SET 1,E RES 7,E RES 5,E RES 3,E RES 1,E BIT 7,E BIT 5,E BIT 3,E BIT 1,E SRL E SRA E RR E RRC E $_B SET 7,H SET 5,H SET 3,H SET 1,H RES 7,H RES 5,H RES 3,H RES 1,H BIT 7,H BIT 5,H BIT 3,H BIT 1,H SRL H SRA H RR H RRC H $_C Table A.2: 2-Byte-Opcodes des Game Boy-Prozessors mit Prefix $CB. SET 6,D SET 4,D SET 2,D SET 0,D RES 6,D RES 4,D RES 2,D RES 0,D BIT 6,D BIT 4,D BIT 2,D BIT 0,D SWAP D SLA D RL D RLC D $_2 SET 7,L SET 5,L SET 3,L SET 1,L RES 7,L RES 5,L RES 3,L RES 1,L BIT 7,L BIT 5,L BIT 3,L BIT 1,L SRL L SRA L RR L RRC L $_D SET 7,[HL] SET 5,[HL] SET 3,[HL] SET 1,[HL] RES 7,[HL] RES 5,[HL] RES 3,[HL] RES 1,[HL] BIT 7,[HL] BIT 5,[HL] BIT 3,[HL] SET 7,A SET 5,A SET 3,A SET 1,A RES 7,A RES 5,A RES 3,A RES 1,A BIT 7,A BIT 5,A BIT 3,A BIT 1,A SRL A SRL [HL] BIT 1,[HL] SRA A SRA [HL] RR A RRC A RRC [HL] RR [HL] $_F $_E A.2 Opcodes 57 Appendix B Special Function Register B.1 Summary Address $FF00 $FF01 $FF02 $FF04 $FF05 $FF06 $FF07 $FF0F Abbreviation Designation Page No. P1 SB SC DIV TIMA TMA TAC IF Joypad Serial Transfer Serial Control Divider Timer Counter Timer Modulo Timer Control Interrupt Flag 59 60 B.2 Detailed description $FF00 – P1 (Joypad) R/W. To read the keys of the joypad. ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ Bit 7: unused Bit 6: unused Bit 5: P15 Output (R/W) Bit 4: P14 Output (R/W) Bit 3: P13 Input (R) Bit 2: P12 Input (R) Bit 1: P11 Input (R) Bit 0: P10 Input (R) 59 Appendix B Special Function Register Tastenverbindung P1 Ein Beispiel zum Auslesen der Tasten findet sich in Abschnitt C.3, Seite 76. $FF01 – SB (Serial Transfer) R/W. Daten zum Senden bzw. Empfangen über die serielle Schnittstelle. $FF02 – SC (Serial Control) R/W. Zum Steuern der seriellen Schnittstelle. ◾ Bit 7: Transfer flag (R/W) W: 0 – unused 1 – Start transfer R: 0 – Transfer finished 1 – Transfer in progress ◾ Bit 0: Clock source (W) 0 – external clock (up to 500 kHz) 1 – internal clock (8 192 Hz) $FF04 – DIV (Divider) R/W. R: Dieser Register wird mit einer Frequenz von fclk /256 inkrementiert, also 214 = 16 384 mal pro Sekunde beim Game Boy Classic und ≈ 16 779 mal pro Sekunde beim Super Game Boy. W: Ein Schreibversuch setzt den Wert von DIV zurück auf $00. $FF05 – TIMA (Timer Counter) R/W. Dieses Register wird mit einer Frequenz, festgelegt im TAC-Register ($FF07), inkrementiert. Beim Überlauf von $FF auf TMA wird ein Timer-Interrupt ausgelöst, siehe $FF0F.2 (Interrupt Flag) und $FFFF.2 (Interrupt Enable). $FF06 – TMA (Timer Modulo) R/W. Beim Überlauf des TIMA-Registers wird dieser Wert geladen. Berechnung der Periodenzeit!!! 60 B.2 Detailed description $FF07 – TAC (Timer Control) R/W. To start/stop the timer and to select the timer frequency. ◾ Bit 2: Timer Start (R/W) 0 – Stop timer 1 – Start timer ◾ Bit 10: Timer increment frequency finc (R/W, Super Game Boy in parentheses) 00: finc = fclk /1 024 4 096 Hz (≈ 4 195 Hz) 01: finc = fclk /16 262 144 Hz (≈ 268 466 Hz) 10: finc = fclk /64 65 536 Hz (≈ 67 177 Hz) 11: finc = fclk /256 16 384 Hz (≈ 16 779 Hz) $FF0F – IF (Interrupt Flag) R/W. If an interrupt occurs, the distinct bit is set in this register. ◾ ◾ ◾ ◾ ◾ ◾ Bits 75: unused Bit 4: Falling edge at joypad pins P10–P13, see also register $FF00 Bit 3: Serial transfer completed, see also register $FF02 Bit 2: Timer overflow, see also register $FF07 Bit 1: LCD control status, see also register $FF41 Bit 0: V-blank, see chapter 9 The priority of the interrupts and their starting address is as follows: Interrupt Priority Starting address V-blank LCD control status Timer overflow Serial transfer completed High→Low at P10–P13 1 2 3 4 5 $0040 $0048 $0050 $0058 $0060 Since there are just 8 Byte of ROM available for each interrupt’s starting address it is used to directly jump to larger memory spaces in order to handle the interrupts. 61 Appendix B Special Function Register $FF10 – NR10 (Sound Mode 1: Sweep) R/W. ◾ Bit 64: Sweep time 000: no Sweep 001: 1/128 s ≈ 7, 8 ms 010: 2/128 s ≈ 15, 6 ms 011: 3/128 s ≈ 23, 4 ms 100: 4/128 s ≈ 31, 3 ms 101: 5/128 s ≈ 39, 1 ms 110: 6/128 s ≈ 46, 9 ms 111: 7/128 s ≈ 54, 7 ms ◾ Bit 3: Frequency increase/decrease 0 – Frequency increases (+) 1 – Frequency decreases (−) ◾ Bit 20: Sweep Shift s (0 to 7) The new frequency f (n + 1) is calculated from the old frequency f (n): f (n + 1) = f (n) (1 ± 1 ). 2s $FF11 – NR11 (Sound Mode 1: Sound Length & Wave Form Duty) ◾ Bit 76: Wave Form Duty 00: 12,5 % 01: 25 % 10: 50 % 11: 75 % ◾ Bit 50: Sound Length t S (0 to 63) If the sound length is not set to continuous following register-bit NR14.6 (see $FF14 below), the sound length is calculated as: 64 − t S s. 256 62 (B.1) B.2 Detailed description $FF12 – NR12 (Sound Mode 1: Envelope) ◾ Bit 74: Inital volume 0000 – Silence 1111 – Maximum ◾ Bit 3: Envelope attenuate/amplify 0 – Volume attenuate 1 – Volume amplify ◾ Bit 20: Envelope time t E (0 to 7) The length of one envelope step is calculated as: tE s. 64 (B.2) $FF13 – NR13 (Sound Mode 1: Low frequency) Lower 8 bits of 11-bit-frequency value x. The upper 3 bits are stored in register NR14 just below. The sound frequency f is obtained from value x as: f = 217 . 211 − x (B.3) A table of sound frequencies for different tones can be found in appendix D.1 and page 79. $FF14 – NR14 (Sound Mode 1: High frequency) ◾ Bit 7: Restart 0 – Do nothing 1 – Sound restarts ◾ Bit 6: Duration 0 – Continuous sound 1 – Sound duration following NR11.50; afterwards NR52.0 is set to 0 ◾ Bit 53: unused ◾ Bit 20: Frequency’s higher 3 bits (0 to 7) More information about the frequency is found in register NR13 just above. $FF16 – NR21 (Sound Mode 2: Sound length & Wave form duty) Exactly the same function as register NR11. For details see there. 63 Appendix B Special Function Register $FF17 – NR22 (Sound Mode 2: Envelope) Exactly the same function as register NR12. For details see there. $FF18 – NR23 (Sound Mode 2: Low frequency) Lower 8 bits of 11-bit-frequency value x. The upper 3 bits are stored in register NR24 just below. The sound frequency f is obtained from value x as: f = 217 . 211 − x (B.4) A table of sound frequencies for different tones can be found in appendix D.1 and page 79. $FF19 – NR24 (Sound Mode 2: High frequency) ◾ Bit 7: Restart 0 – Do nothing 1 – Sound restarts ◾ Bit 6: Duration 0 – Continuous sound 1 – Sound duration following NR21.50; afterwards NR52.1 is set to 0 ◾ Bit 53: unused ◾ Bit 20: Frequency’s higher 3 bits (0 to 7) More information about the frequency is found in register NR13 just above. $FF1A – NR30 (Sound Mode 3: Sound on/off) $FF1B – NR31 (Sound Mode 3: Sound length) ◾ Bit 70: Sound Length t S (0 to 255) If the sound length is not set to continuous following register-bit NR34.6 (see $FF1E below), the sound length is calculated as: 256 − t S s. 2 64 (B.5) B.2 Detailed description $FF1C – NR32 (Sound Mode 3: Output level) ◾ Bit 65: Output level 00: Mute 01: Wave pattern as it is 10: Wave pattern shifted once to the right 11: Wave pattern shifted twice to the right For the wave pattern itself see ff30:$FF3F on page 66. $FF1D – NR33 (Sound Mode 3: Low frequency) Lower 8 bits of 11-bit-frequency value x. The upper 3 bits are stored in register NR34 just below. The sound frequency f is obtained from value x as: f = 216 . 211 − x (B.6) Note: the frequency is half of those of sound channels 1 and 2. The actual sound frequency further depends on the contents of the wave pattern RAM. $FF1E – NR34 (Sound Mode 3: High frequency) ◾ Bit 7: Restart 0 – Do nothing 1 – Sound restarts ◾ Bit 6: Duration 0 – Continuous sound 1 – Sound duration following NR31.50; afterwards NR52.2 is set to 0 ◾ Bit 53: unused ◾ Bit 20: Frequency’s higher 3 bits (0 to 7) More information about the frequency is found in register NR13 just above. $FF20 – NR41 (Sound Mode 4: Sound length) ◾ Bit 76: unused ◾ Bit 50: Sound Length t S (0 to 63) 65 Appendix B Special Function Register If the sound length is not set to continuous following register-bit NR44.6 (see $FF23 below), the sound length is calculated as: 64 − t S s. 256 $FF21 – NR42 (Sound Mode 4: Envelope) todo $FF22 – NR43 (Sound Mode 4: Polynomial counter) todo $FF23 – NR44 (Sound Mode 4: Initial) todo $FF24 – NR50 (Channel Control: Volume) todo $FF25 – NR51 (Channel Control: Output mapping) todo $FF26 – NR52 (Channel Control: On/off) todo $FF30:$FF3F – Wave pattern RAM R/W. 66 (B.7) B.2 Detailed description $FF40 – LCDC (LCD control) R/W. ◾ Bit 7: Display on/off 0 – Display off1 1 – Display on ◾ Bit 6: Memory area window tile map 0: $9800–$9BFF 1: $9C00–$9FFF ◾ Bit 5: Show window 0 – Window off 1 – Window on ◾ Bit 4: Memory area for background & window tile data 0: $8800–$97FF 1: $8000–$8FFF (Same area as sprite data) ◾ Bit 3: Memory area for background tile map 0: $9800–$9BFF 1: $9C00–$9FFF ◾ Bit 2: Sprite size (W × H) 0 – 8 × 8 1 – 8 × 16 ◾ Bit 1: Show sprites 0 – Sprites off 1 – Sprites on ◾ Bit 0: Show background 0 – Background off 1 – Background on $FF41 – STAT (LCD Status) todo $FF42 – SCY (Scroll Y) Y-scroll-position of the background. $00 is top. 1 Switching off the display is only allowed in v-blank mode, that is, if the register LY ≥ $90, see also register $FF44. 67 Appendix B Special Function Register $FF43 – SCX (Scroll X) X-scroll-position of the background. $00 is leftmost. $FF44 – LY (Y-position) Indicates the vertical line index to which the data is currently transferred to the LCD. Values of 0 to 143 ($8F) indicate operation on visible screen, values of 144 $90 to 153 $99 indicate the v-blank period. After 153 it starts again from 0. $FF45 – LYC (Compare y-position) LYC is compared with the current value of LY. If they have equal values, the coincident flag in the STAT register (ff41.2) is set. $FF46 – DMA (Direct memory access transfer & start address) todo $FF47 – BGP (Background & window palette) This palette is used to assign values of the background/window to a distinct gray scale. ◾ ◾ ◾ ◾ Bits 76: Color for data &11 (Black) Bits 54: Color for data &10 (Dark-gray) Bits 32: Color for data &01 (Ligh-gray) Bits 10: Color for data &00 (White) If the values should be assign 1:1, the value of $FF47 would be &11100100 or $E4, respectively. In order to invert the colors, the value would be &00011011 or $1B, respectively. $FF48 – OBP0 (Object palette 0) This palette is used to assign values of object palette 0 to a distinct gray scale. It works like BGP (see above) except that each values of &00 will be transparent. 68 B.2 Detailed description $FF49 – OBP1 (Object palette 1) This palette is used to assign values of object palette 1 to a distinct gray scale. It works exactly like OBP1 (see above). $FF4A – WY (Window y-position) todo $FF4B – WX (Window x-position) todo $FFFF – IE (Interrupt enable) Interrupt enable is used to enable/disable distinct interrupts. If an interupt occurs, the corresponding flags are set in register IF ($FF0F). ◾ ◾ ◾ ◾ ◾ ◾ Bits 75: unused Bit 4: Falling edge at joypad pins P10–P13, see also register $FF00 Bit 3: Serial transfer completed, see also register $FF02 Bit 2: Timer overflow, see also register $FF07 Bit 1: LCD control status, see also register $FF41 Bit 0: V-blank, see chapter 9 69 Appendix C Code Schnipsel Kleine Code-Sammlung. C-Code als Pseudocode. C.1 Bedingungen An dieser Stelle werden die Register A und B miteinander verglichen. Statt B kann auch jedes andere Register oder eine Konstante verwendet werden. Der Vergleich bezieht sich auf 8-Bit-Zahlen ohne Vorzeichen. A=B C: unsigned char A, B; // eigentlich Register A, B if (A == B) { ; // true } Assembler: cp b jr nz,.next ; true: a == b .next: Alternative mit else in C: if (A == B) { ; // true } else { ; // false (A != B) } Assembler: 71 Appendix C Code Schnipsel cp b jr nz,.false ; true: a == b jr .next .false: ; false: a != b .next: A≠B C: unsigned char A, B; // eigentlich Register A, B if (A != B) { ; // true } Assembler: cp b jr z,.next ; true: a != b .next: Alternative mit else, siehe A == B oben, nur umgekehrt. A<B C: if (A < B) { ; // true } Assembler: cp b jr nc,.next ; true: a < b .next: Alternative mit else in C: 72 C.1 Bedingungen if (A < B) { ; // true } else { ; // false (A >= B) } Assembler: cp b jr c,.false ; true: a < b jr .next .false: ; false: a >= b .next: A>B C: if (A > B) { ; // true } Assembler: cp b jr z,.next ; jump if a==b jr c,.next ; jump if a<b ; true: a > b .next: Alternative mit else in C: if (A > B) { ; // true } else { ; // false (A <= B) } Assembler: 73 Appendix C Code Schnipsel cp b jr z,.false ; jump if a==b jr c,.false ; jump if a<b ; true: a <= b jr .next .false: ; false: a > b .next: A≤B C: if (A <= B) { ; // true } Assembler siehe A > B oben, Variante mit else. A≥B C: if (A >= B) { ; // true } Assembler siehe A < B oben, Variante mit else. BC ≠ 0 C: unsigned short BC; if (BC) { ; // true } Assembler: ld or jr 74 a,b c z,.next C.2 Schleifen ; true: bc != 0 .next: C.2 Schleifen Schleife mit 256 ($100) Durchgängen Hier wird eine do-while-Schleife implementiert, wobei ausgenützt wird, dass ein Dekrementieren von B = 0 zu B = 255 führt. Größe: 5 Byte und eigener Code Laufzeit: 1025 Zyklen und eigener Code mal 256. ld b,$00 .loop: ; 256x ausgefuehrt dec b jr nz,.loop Beispiel: Es soll ein 256 Byte großer Bereich im internen RAM von $DF00–$DFFF mit 0 initialisiert werden. Größe: 10 Byte Laufzeit: 1285 Zyklen ld xor ld .loop: ld dec jr hl,$dfff ; endadresse! a ;a=0 b,$00 [hl−],a b nz,.loop Schleife mit n8 ×256 ($100) Durchgängen ld ld .loop: ; n8 dec jr dec jr c,n8 b,$00 x 256 ausgefuehrt b nz,.loop c nz,.loop 75 Appendix C Code Schnipsel Beispiel: Es soll das gesamte Video-RAM von $8000–$9FFF (Größe $2000 bzw. 8 kByte) mit 0 initialisiert werden. ld xor ld ld .loop: ld dec jr dec jr hl,$9fff ; endadresse! a ;a=0 c,$20 ; $20 x $100 = $2000 bzw. 32 x 256 = 8192 b,$00 [hl−],a b nz,.loop c nz,.loop Schleife mit n16 Durchgängen C.3 Read the joypad Folgendes Programm liest die gedrückten Tasten aus und speichert diese in die Variable keyData. Tasten, die seit dem letzten Auslesen neu gedrückt wurden, werden in keyDataEdge gespeichert. Jedem Bit wird auf diese Weise eine Taste zugeordnet: ◾ ◾ ◾ ◾ ◾ ◾ ◾ ◾ Bit 7: ↓ Bit 6: ↑ Bit 5: ← Bit 4: → Bit 3: Start Bit 2: Select Bit 1: B Bit 0: A section "Variables",BSS keyData: ds 1 keyDataEdge: ds 1 section "Read Keypad",HOME ReadKeypad: ld a,$20 ; &00100000 (P15=1, P14=0) ld [$ff00],a ; write to P1 76 C.4 Optimized alternatives rept ld endr cpl and swap ld ld ld rept ld endr cpl and or ld ld xor and ld ld ld ld ld ret 6 ; asm: repeat 4x a,[$ff00] ; read in P1 several times (bounce!) ; asm: end repeat ; invert data a,$0f ; just bits 3−0 are interesting a ; bits 3−0 −> bits 7−4 (high nibble) b,a ; copy to b a,$10 ; $00010000 (P15=0, P14=1) [$ff00],a ; write to P1 6 ; asm: repeat 4x a,[$ff00] ; read in P1 several times (bounce!) ; asm: end repeat ; invert data a,$0f ; just bits 3−0 are interesting b ; merge all keys to a b,a ; copy new data to b a,[keyData] ; copy old data to a b ; find the differences b ; find keys that are newly pressed down [keyDataEdge],a ; copy this edge data to the variable a,b ; restore new data from b [keyData],a ; copy this data to the variable a,$30 ; &00110000 (P15=1, P14=1) [$ff00],a ; reset to high ; return C.4 Optimized alternatives Clear the accumulator Variante 1 (2 Byte, 2 Zyklen): ld a,$00 ; flags unveraendert Variante 2 (1 Byte, 1 Zyklus): xor a ; flags: C=0, Z=1 Vergleiche A mit $00 Variante 1 (2 Byte, 2 Zyklen): 77 Appendix C Code Schnipsel cp $00 Variante 2 (1 Byte, 1 Zyklus): or a Variante 3 (1 Byte, 1 Zyklus): and a Vertauschen von DE und HL Variante 1: Dreieckstausch (6 Byte, 6 Zyklen): ld ld ld ld ld ld a,d ; je 1 byte, 1 zyklus d,h h,a a,e e,l l,a Variante 2 (4 Byte, 8 Zyklen): push ld ld pop de d,h e,l hl ; ; ; ; 1 1 1 1 Byte, Byte, Byte, Byte, 3 1 1 3 Zyklen Zyklus Zyklus Zyklen HL mit 16-Bit-Wert aus Adresse laden Variante 1 (8 Byte, 10 Zyklen): ld ld ld ld a,[addr] l,a a,[addr+1] h,a ; ; ; ; 3 1 3 1 Byte, Byte, Byte, Byte, 4 1 4 1 Zyklen Zyklus Zyklen Zyklus Variante 2 (6 Byte, 7 Zyklen) ld ld ld ld 78 hl,addr a,[hl+] h,[hl] l,a ; ; ; ; 3 1 1 1 Byte, Byte, Byte, Byte, 2 2 2 1 Zyklen Zyklen Zyklen Zyklus Appendix D Tabellen D.1 Tonwiedergabe Das nachfolgende Listing enthält Makros mit Konstanten-Definitionen für die Frequenzen und die Dauer verschiedener Töne. Die Frequenzen (Makro FREQ440) können für die Frequenzregister NR14 und NR13 ($FF14 und $FF13) bzw. NR24 und NR23 ($FF19 und $FF18) verwendet werden. Zur Berechnung der Werte muss zunächst die Frequenz der Töne berechnet werden. Bei einer Erhöhung eines Tons um eine Oktave verdoppelt sich dessen Frequenz. Da unser Ohr ein logarithmisches Verständnis für Töne hat, müssen die 12 Halbtöne zwischen zwei Oktaven ebenfalls logarthmisch verteilt liegen. Es sind also keine konstanten Frequenzabstände, sondern konstante Frequenzverhältnisse zwischen jeweils zwei benachbarten Halbtönen (bei gleichmäßiger Stimmung). Habe Ton 1 eine Frequenz f0 und der Halbton darüber die Frequenz f1 , so unterscheiden sich die beiden Frequenzen durch einen Faktor k = f1 / f0 . Geht man einen Halbton weiter zu f2 , so ist f2 / f1 ebenfalls k, oder f2 / f0 = k 2 . Eine Oktave entspricht daher einem Faktor k 12 = 2. Nach Logarithmieren erhält man also den Faktor k = 21/12 . Geht man nun von einer Norm, z. B. dem Kammerton a’ mit f0 = 440 Hz aus, so errechnen sich die restlichen Halbtöne zu f n = 440 Hz ⋅ 2n/12 , wobei n eine ganze Zahl ist (z. B. −33 für eine großes C oder 26 für ein h”’). Der in die Frequenzregister zu speichernde Wert x kann durch Umformung von (B.6) auf Seite 65 ermittelt werden: 26 x = [211 (1 − )] , fn wobei hier die eckigen Klammern für eine Rundung auf ganze Zahlen stehen. Für das Makro wurden Werte für die Töne vom großen C ausgehend (≈ 65 Hz, tiefstmögliche Frequenz: 64 Hz) über 5 Oktaven berechnet, was einen Großteil der benötigten Töne abdecken sollte. 79 Appendix D Tabellen Für die Festlegung der Tondauer gibt es im Prinzip zwei Möglichkeiten: 1. Verwendung von Bit 50 der Register NR11 ($FF11) bzw. NR21 ($FF11), siehe auch (B.7) auf Seite 66 2. Unter Benutzung des Timers und weiterer Frequenzteilung mittels Variable Wenn man sich Variante 1 etwas genauer ansieht, stellt man fest, dass die längste mögliche Tondauer 1/4 Sekunde beträgt. Das mag vielleicht für ein Paganini Caprice Nr. 24 ausreichend sein, für normale Musik aber doch ein wenig zu kurz. Zur Wiedergabe von Musik ist also Variante 2 vorzuziehen. Stellt sich die Frage: Welche Periodendauer soll der Timer sinnvollerweise haben? Zur Beantwortung muss man sich zunächst überlegen, welche die kürzeste Note im Stück vorkommt. Die kürzeste Note muss genauso präzise gespielt werden wie sämtliche andere Noten. 80 Appendix E The boot ROMs* 81 Appendix F Drawings This appendix features drawings of particular parts of the Game Boy that may be useful when someone is interested to do some own designs. F.1 Cartridge PCB and Cartridge Connector 83