rst? It's high time we give them some love and care!
The concept of calling a function is that at some point in the flow, the flow is interrupted, a separate piece of code is ran, and then the flow resumes, optionally using some of the function's calculations. On the GB, this is done using the
The principle is, again, that the function "returns" to the main flow. To do that, it need to save where the "calling" flow was... My, my, didn't we just see that the stack was perfect for saving stuff? Well, that's exactly what happens!
; Let's say that `Function` is a label call Function ; equivalent to (again, these instructions are illustrative but **invalid**) push pc ; But PC equals the address after the following instruction jp Function .return ; This is the address whose value gets pushed onto the stack
(If you're not sure how that works, read
ret's description below; that should make it clearer.)
Oh, and also, just like
call can be executed conditionally.
call nz, AFunctionCalledOnlyIfZIsReset
Now, a function needs to tell the CPU when it's over, and when control need to be passed back to the calling code. This is done by the
ret operation, which is basically
pop pc. And this instruction can be used conditionally too! Here's an example:
Memcpy: ld a, [de] ld [hli], a inc de dec bc ld a, b or c jr nz, Memcpy ret
If you remember from the Hello World chapter, this looks like the piece of code we used to copy data to VRAM. This is useful to avoid repeating blocks of code:
ld de, FontTiles ld hl, $9000 ld bc, FontTilesEnd - FontTiles call Memcpy
Note that the
ret doesn't have to be at the end of the function!
ld de, DefaultPlayerName ld hl, wPlayerName call Strcpy ; (...) ; Copy a string up to but not including the first NUL character ; @param de A pointer to the string to be copied ; @param hl A pointer to the beginning of the destination buffer ; @return de A pointer to the byte after the source string's terminating byte ; @return hl A pointer to the byte after the last copied byte ; @return a Zero ; @return flags C reset, Z set Strcpy: ld a, [de] inc de and a ret z ld [hli], a jr Strcpy
An announcement about documentation
You can see that I inserted a huge comment before the
Strcpy function. This is to help document what it does, etc. I recommend using a format similar to this one, because it's clear and concise. I use
@param to indicate which registers, flags and memory addresses the function uses as input,
@return to document the effects that the function has that are consistent, and
@destroy to document the effects it has which are either inconsistent or too complex to explain. I recommend taking the time to write and keep this kind of comment to date, to help you maintain your code.