Anonymous user
GB Programming: Difference between revisions
Minor grammar fixes
>Torchickens No edit summary |
>Torchickens (Minor grammar fixes) |
||
Line 1:
Welcome to this tutorial
Our goal will first be to create [[arbitrary code execution]] programs, but later sections of this tutorial will give you tools for more general-purpose programming, so you'll be able to create your own games.
Let's get started
Line 9:
In this part is a collection of different terms, concepts and notations that are '''vital''' for the rest of this tutorial. Do NOT skip anything here unless the text specifies you can. I mean it.
If you don't understand something later on, read
===Numeric systems===
Line 28:
However, decimal is the base humans like to count in. But computers don't. Instead, they prefer '''binary'''. Binary is '''base 2''', that is, instead of working with powers of 10, we work with powers of 2. Also, only 2 symbols are allowed, 0 and 1. Each of them is called a '''bit'''.
This paragraph is some trivia about why computers use binary instead of decimal. You can skip it if you
To differentiate decimal numbers from binary numbers, binary numbers will be
Here is an example :
Line 61:
</pre>
Why using hexadecimal
<pre>
$9 = %1001
Line 70:
This way, we have a more readable way of writing numbers that can be converted to binary in a snap.
For the rest of this tutorial, we will mostly be using hexadecimal, but always remember the binary lying down below
==A dip into
===Registers===
Registers are sections of RAM within the CPU itself. That is what you will be working with, alongside memory. But we'll see memory later.
There are 8 different registers, which can be actually paired up. These are A, B, C, D, E, F, H and L. These are NOT hex digits, so beware
Any of these registers can hold an '''unsigned 8-bit value'''. That means :
Line 95:
* A is the '''Accumulator'''. It is the register you have to use to make arithmetic operations, and most of the time, memory access.
* B is usually a 8-bit counter.
* C is also used as a 8-bit counter, but also for port access. We'll see that
* D, E, H and L have no special attribute as 8-bit. However, when paired, they do.
* F holds the CPU's '''Flags'''. It is very special, as you cannot use it as a general-purpose register. You can't even directly access it
* HL is quite the equivalent of A, but is 16-bit. Its name is because it stores the '''High''' and '''Low''' bytes of a memory address.
* BC is mostly used as a '''Byte Counter'''. It can also be used together with A to access memory.
Line 108:
|Store the value of ''source'' into ''destination''.
|}
Did I mention that nothing is case-sensitive
However, you can't do LD as you wish, there are restrictions :
Line 408:
Trying to do something like ''ld a, $100'' isn't possible. Like, physically impossible. You'll see why much, much later.
Note that ''ld a, -1'' is valid, but actually, the "-1" wraps. Storing -1 will truly store 255 in a 8-bit register, and 65535 in a 16-bit register. Why
Notice that F and AF aren't usable anywhere. Actually, only a few instructions use them.
Line 414:
===Negative numbers===
Time to confess
I've told you, "individual registers can hold unsigned 8-bit values, and pairs unsigned 16-bit values". However, these aren't true
What we will be doing is cutting our number range in half, and telling one half is composed of negative numbers. But how to distinguish positive and negative numbers
How to multiply by -1
* Calculate zero minus your number (just like in real life). However, you should consider 0 the same as 256 (in 8-bit mode) or 65536 (in 16-bit mode).
* Flip the state of every bit, then add one.
Line 429:
Add 1 %10000000
</pre>
So, uh, -(-128) = -128
Now, let's see how the CPU handles the difference between unsigned and signed values. Surprise, it doesn't
<pre>
unsigned signed
Line 438:
%1 00000000 = 256 = 0 (Disqualify ninth bit)
</pre>
And, you just saw why I told you to consider 0 the same as 256 : they are similar
===Memory===
Finally
Ever wondered why you could open a JPEG in Word
How is every byte differentiated from its neighbors
So, how does running a program works
So now, how to access memory
To access the memory location pointed to by HL, just do... (hl)
So, to retrieve the value at memory address $5611 into register A : ''ld a, ($6511)''
Line 460:
Remember to refer to the chart above for the legal LD combinations.
Obviously, ''ld ($6511), a'' will overwrite the previous value stored here. But ''ld ($6511), hl'' will store a 16-bit value, which is a word long, that is two bytes long
For those wondering, ''ld a, ($6511)'' leaves ($6511) untouched.
Line 466:
==Flags==
Remember that "special" F register
Here are the 8 flags :
Line 474:
|S||Z||-||H||-||P/V||N||C
|}
Both "-" are
===S : Sign===
Line 505:
==Manipulating data==
===Instructions get
Let's get these :
{| class="wikitable"
Line 559:
If you want to get information about any instruction, go [http://tutorials.eeems.ca/ASMin28Days/ref/z80is.html there].
Q : Hey, but where's MULT
A : Nowhere :D To multiply, you must write your own routines
For the rest of the tutorial, you'll see some text prefixed by a ";". These are comments, and are NOT part of the code. This line : "ld (hl), a ; Store the mon's ID" will be interpreted as "ld (hl), a". Everything following a ";" is ignored.
Line 588:
add a, 119
</pre>
What value will hold A
Thus, the result is A equals 66 = %01000010, and the C flag is set.
Line 594:
===Register pairs and RAM===
Let's say you run a ld hl, $D361. $D361 is put into HL, but since it is registers H and L paired up, what happen to them
Because two hex digits mean one byte, $D3, as well as $61, is a byte. Since $D3 and H are leftmost in both cases, ld hl, $D361 is actually a shorter form of ld h, $D3 then ld l, $61.
Line 602:
Stop here, and remember this until it becomes natural to you. Because this "little-endian"ness is very tricky for beginners. It is ''very'' important when working with memory.
Here is an exercise : what values will ($C000) to ($C00F) contain after this code is ran
Initial values :
Line 633:
==Stacks==
===A stack
No it's not. It's a data structure that has the cool property of not being fixed-length. How does it work
In our case, we will do it by saving the top of the stack as a memory address. This value is called the ''stack pointer''. Here is an example, with the stack growing to the right :
Line 671:
===Coding a stack===
Let's say we have our stack pointer saved at memory address $C000 (because it is a 16-bit value, it also uses memory address $C001
To push register DE :
Line 694:
===Good news===
Okay, coding a stack is cool, but... isn't there a faster way of doing it
{| class="wikitable"
|PUSH reg16
Line 736:
Note that the stack grows '''downwards''' (ie, PUSH reduces the value from SP, and POP augments it). Also, POP doesn't alter memory.
You cannot PUSH / POP with 8-bit registers. Instead, to save register B, you '''must''' ''push bc''. You don't have to push and pop to the same register
<pre>
push af
Line 744:
is completely valid. (Note that E's value after the POP is equal to F's when PUSHing, so this is the only way to directly access the F register)
Beware with the stack, even more when you're not coding your own game : everyone uses the stack ; even the CPU
==Control structures==
===Rollin' around===
...at the speed of sound
Up until now, we've seen only programs that begin somewhere and that are ran top to bottom, in that order. However, this never happens in a more complex context. So, let's see how to manipulate code flow
We have two instructions that allow execution to jump somewhere else in memory :
Line 761:
|Has execution jumping over offset8 bytes
|}
What's the difference
First, JP can go '''anywhere'''. JP tells the CPU "jump to this memory address". JR is much more limited, as it can only reach a signed 8-bit range (128 bytes backwards, or 127 bytes forwards).
Line 769:
Third, JR takes 7 or 12 CPU cycles to run, whereas JP always takes 10.
And this brings us to the next part
===Conditionals===
JP and JR can be executed in unconditional ways, meaning the jump will always occur. This can be useful, but sometimes we don't want that. And that's where flags come in handy
{| class="wikitable"
|JP condition, label
Line 797:
==Solutions to the exercises==
===Instructions get
B can be swapped with any other register (except A)
{| class="wikitable"
Line 863:
sub a, b ; A = A - B = $06 - $DE = $06 + (-$DE) = $06 + ($21 + $01) = $28, C flag = 0
<br/>
Notice here that doing ''sub a, b'' actually increased A's value
inc (hl) ; (HL) = ($C004) = $DF
|