You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/part1/jumps.md
+20-23Lines changed: 20 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,26 +10,26 @@ So far, all the code we have seen was linear: it executes top to bottom.
10
10
But this doesn't scale: sometimes, we need to perform certain actions depending on the result of others ("if the crêpes start sticking, grease the pan again"), and sometimes, we need to perform actions repeatedly ("If there is some batter left, repeat from step 5").
11
11
12
12
Both of these imply reading the recipe non-linearly.
13
-
In assembly, this is achieved using *jumps*.
13
+
In assembly, this is achieved using _jumps_.
14
14
15
15
The CPU has a special-purpose register called "PC", for Program Counter.
16
16
It contains the address of the instruction currently being executed[^pc_updates], like how you'd keep in mind the number of the recipe step you're currently doing.
17
-
PC increases automatically as the CPU reads instructions, so "by default" they are read sequentially; however, jump instructions allow writing a different value to PC, effectively *jumping* to another piece of the program.
17
+
PC increases automatically as the CPU reads instructions, so "by default" they are read sequentially; however, jump instructions allow writing a different value to PC, effectively _jumping_ to another piece of the program.
18
18
Hence the name.
19
19
20
20
Okay, so, let's talk about those jump instructions, shall we?
|Jump Relative |`jr`| Jump to a location close by|
27
+
|Call |`call`| Call a subroutine|
28
+
|Return |`ret`| Return from a subroutine|
29
29
30
30
We will focus on `jp` for now.
31
31
`jp`, such as the one line {{#line_no_of "^\s*jp" ../assets/hello-world.asm}}, simply sets PC to its argument, jumping execution there.
32
-
In other words, after executing `jp EntryPoint` (line {{#line_no_of "^\s*jp EntryPoint" ../assets/hello-world.asm}}), the next instruction executed is the one below `EntryPoint` (line <!-- should be {{#line_no_of "^\s*EntryPoint:" ../assets/hello-world.asm}} + 1 -->16).
32
+
In other words, after executing `jp EntryPoint` (line {{#line_no_of "^\s*jp EntryPoint" ../assets/hello-world.asm}}), the next instruction executed is the one below `EntryPoint` (line <!-- should be {{#line_no_of "^\s*EntryPoint:" ../assets/hello-world.asm}} + 1 -->11).
33
33
34
34
:::tip:🤔
35
35
@@ -40,7 +40,7 @@ Don't worry, we will see later why it's required.
40
40
41
41
## Conditional jumps
42
42
43
-
Now to the *really* interesting part.
43
+
Now to the _really_ interesting part.
44
44
Let's examine the loop responsible for copying tiles:
@@ -56,7 +56,7 @@ If you're having trouble, try going to the next lesson, watch the code execute s
56
56
57
57
First, we copy `Tiles`, the address of the first byte of tile data, into `de`.
58
58
Then, we set `hl` to $9000, which is the address where we will start copying the tile data to.
59
-
`ld bc, TilesEnd - Tiles` sets `bc` to the length of the tile data: `TilesEnd` is the address of the first byte *after* the tile data, so subtracting `Tiles` to that yields the length.
59
+
`ld bc, TilesEnd - Tiles` sets `bc` to the length of the tile data: `TilesEnd` is the address of the first byte _after_ the tile data, so subtracting `Tiles` to that yields the length.
60
60
61
61
So, basically:
62
62
@@ -87,22 +87,19 @@ See, it's possible to **conditionally** "take" a jump depending on the state of
|Zero |`z`| Z is set (last operation had a result of 0)|
93
+
|Non-zero |`nz`| Z is not set (last operation had a non-zero result)|
94
+
|Carry |`c`| C is set (last operation overflowed)|
95
+
|No carry |`nc`| C is not set (last operation did not overflow)|
96
96
97
97
Thus, `jp nz, CopyTiles` can be read as "if the Z flag is not set, then jump to `CopyTiles`".
98
-
Since we're jumping *backwards*, we will repeat the instructions again: we have just created a **loop**!
98
+
Since we're jumping _backwards_, we will repeat the instructions again: we have just created a **loop**!
99
99
100
-
Okay, we've been talking about the code a lot, and we have seen it run, but we haven't really seen *how* it runs.
100
+
Okay, we've been talking about the code a lot, and we have seen it run, but we haven't really seen _how_ it runs.
101
101
Let's watch the magic unfold in slow-motion in the next lesson!
102
102
103
103
---
104
104
105
-
[^pc_updates]:
106
-
Not exactly; instructions may be several bytes long, and PC increments after reading each byte.
107
-
Notably, this means that when an instruction finishes executing, PC is pointing to the following instruction.
108
-
Still, it's pretty much "where the CPU is currently reading from", but it's better to keep it simple and avoid mentioning instruction encoding for now.
105
+
[^pc_updates]: Not exactly; instructions may be several bytes long, and PC increments after reading each byte. Notably, this means that when an instruction finishes executing, PC is pointing to the following instruction. Still, it's pretty much "where the CPU is currently reading from", but it's better to keep it simple and avoid mentioning instruction encoding for now.
0 commit comments