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