fix other mandelbrot variants
[mu.git] / tutorial / index.md
blob2cc95c09e25624c2805b4752cda35df3fde8df29
1 # A guided tour of Mu on x86 computers
3 _by Kartik Agaram and [sejo](https://compudanzas.net)_
5 [Mu](https://github.com/akkartik/mu) shrinks all the software in a computer
6 until it can (in principle) fit in a single head. Sensible error messages with
7 as little code as possible, starting all the way from your (x86) processor's
8 instruction set. Everything easy to change to your needs
9 ([habitable](http://akkartik.name/post/habitability)), everything easy to
10 check up on ([auditable](http://akkartik.name/post/neighborhood)).
12 This page is a guided tour through [Mu's Readme](https://github.com/akkartik/mu#readme)
13 and reference documentation. We'll start out really slow and gradually
14 accelerate as we build up skills. By the end of it all, I hope you'll be able
15 to program your processor to run some small graphical programs. The programs
16 will only use a small subset of your computer's capabilities; there's still a
17 lot I don't know and therefore cannot teach. However, the programs will run on
18 a _real_ processor without needing any other intermediary software.
20 _Prerequisites_
22 You will need:
24 * A computer with an x86 processor running Linux. Mu is designed to eventually
25   escape Linux, but still needs some _host_ environment for now. Other
26   platforms will also do (BSD, Mac OS, Windows Subsystem for Linux), but be
27   warned that things will be _much_ (~20x) slower.
28 * Some fluency in typing commands at the terminal and interpreting their
29   output.
30 * Fluency with some text editor. Things like undo, copying and pasting text,
31   and saving work in files. A little experience programming in _some_ language
32   is also handy.
33 * [Git](https://git-scm.com) for version control.
34 * [QEMU](https://www.qemu.org) for emulating a processor without Linux.
35 * Basic knowledge of number bases, and the difference between decimal and
36   hexadecimal numbers.
37 * Basic knowledge of the inside of a processor, such as the difference between
38   a small number of registers and a large number of locations in memory.
40 If you have trouble with any of this, [I'm always nearby and available to
41 answer questions](http://akkartik.name/contact). The prerequisites are just
42 things I haven't figured out how to explain yet. In particular, I want this
43 page to be accessible to people who are in the process of learning
44 programming, but I'm sure it isn't good enough yet for that. Ask me questions
45 and help me improve it.
47 ## Task 1: getting started
49 Read the first half of [the Readme](https://github.com/akkartik/mu/blob/main/README.md)
50 (stop before the section on “Syntax”). Can you figure out the
51 commands to prepare Mu on your computer?
53 Open a terminal and run the following commands to prepare Mu on your computer:
55 ```
56 git clone https://github.com/akkartik/mu
57 cd mu
58 ```
60 Run a small program to start:
62 ```
63 ./translate tutorial/task1.mu
64 qemu-system-i386 code.img
65 ```
67 If you aren't on Linux (or Windows Subsystem for Linux), the command for
68 creating `code.img` will be slightly different:
70 ```
71 ./translate_emulated tutorial/task1.mu
72 qemu-system-i386 code.img
73 ```
75 Either way, you should see this:
77 <img alt='screenshot of hello world on the Mu computer' src='task1.png'>
79 If you have any trouble at this point, don't waste _any_ time thinking about
80 it. Just [get in touch](http://akkartik.name/contact).
82 (You can look at `tutorial/task1.mu` at this point if you like. It's just 3
83 lines long. But don't worry if it doesn't make much sense.)
85 ## Task 2: running automated tests
87 Here's a new program to run:
89 ```
90 ./translate tutorial/task2.mu
91 qemu-system-i386 code.img
92 ```
94 (As before, I'll leave you to substitute `translate` with `translate_emulated`
95 if you're not on Linux.)
97 This time the screen will look like this:
99 <img alt='screenshot of failing test on the Mu computer' src='task2.png'>
101 Each of the dots represents an automated _test_, a little self-contained and
102 automated program run and its results verified. Mu comes with a lot of tests
103 (every function starting with 'test-' is a test), and it always runs all tests
104 on boot before it runs any program. You may have missed the dots when you ran
105 Task 1 because there were no failures. They were printed on the screen and
106 then immediately erased. In Task 2, however, we've deliberately included a
107 failing test. When any tests fail, Mu will immediately stop, showing you
108 messages from failing tests and implicitly asking you to first fix them. A lot
109 of learning programming is about building a sense for when you need to write
110 tests for the code you write.
112 (Don't worry just yet about what the message in the middle of all the dots means.)
114 ## Task 3: configure your text editor
116 So far we haven't used a text editor yet, but we will now be starting to do
117 so. Before we do, it's worth spending a little bit of time setting your
118 preferred editor up to be a little more ergonomic. Mu comes with _syntax
119 highlighting_ settings for a few common text editors in the `editor/`
120 sub-directory. If you don't see your text editor there, or if you don't know
121 what to do with those files, [get in touch!](http://akkartik.name/contact)
122 Here's what my editor (Vim) looks like with these settings on the program of
123 Task 1:
125 <img alt='Vim text editor rendering some colors in a Mu program' src='task3.png'>
127 It's particularly useful to highlight _comments_ which the computer ignores
128 (everything on a line after a `#` character) and _strings_ within `""` double
129 quotes.
131 ## Task 4: your first Mu statement
133 Mu is a statement-oriented language. Most statements translate into a single
134 instruction to the x86 processor. Quickly read the first two sections of the
135 [Mu reference](https://github.com/akkartik/mu/blob/main/mu.md) (about
136 functions and variables) to learn a little bit about it. It's ok if it doesn't
137 all make sense just yet. We'll reread it later.
139 Here's a skeleton of a Mu function that's missing a single statement.
142 fn the-answer -> _/eax: int {
143   var result/eax: int <- copy 0
144   # insert your statement below {
146   # }
147   return result
151 Try running it now:
153 ./translate tutorial/task4.mu
154 qemu-system-i386 code.img
157 (As before, I'll leave you to substitute `translate` with `translate_emulated`
158 if you're not on Linux.)
160 You should see a failing test that looks something like this:
162 <img alt='screenshot of the initial (failing) state of task 4' src='task4-initial.png'>
164 Open `tutorial/task4.mu` in your text editor. Think about how to add a line
165 between the `{}` lines to make `the-answer` return 42. Rerun the above
166 commands. You'll know you got it right when all the tests pass, i.e. when the
167 rows of dots and text above are replaced by an empty screen.
169 Don't be afraid to run the above commands over and over again as you try out
170 different solutions. Here's a way to run them together so they're easy to
171 repeat.
174 ./translate tutorial/task4.mu  &&  qemu-system-i386 code.img
177 In programming there is no penalty for making mistakes, and once you arrive at
178 the correct solution you have it forever. As always, [feel free to ping me and
179 ask questions or share your experience](http://akkartik.name/contact).
181 Mu statements can have _outputs_ on the left (before the `<-`) and _inouts_
182 (either inputs or outputs) on the right, after the instruction name. The order
183 matters.
185 One gotcha to keep in mind is that numbers in Mu must always be in hexadecimal
186 notation, starting with `0x`. Use a calculator on your computer or phone to
187 convert 42 to hexadecimal, or [this page on your web browser](http://akkartik.github.io/mu/tutorial/converter.html).
189 ## Task 5: variables in registers, variables in memory
191 We'll now practice managing one variable in a register (like last time) and
192 a second one in memory. To prepare for this, reread the first two sections of
193 the [Mu reference](https://github.com/akkartik/mu/blob/main/mu.md). The
194 section on [integer arithmetic](https://github.com/akkartik/mu/blob/main/mu.md#integer-arithmetic)
195 also provides a useful cheatsheet of the different forms of instructions you
196 will need.
198 Here's the exercise, with comments starting with `#` highlighting the gaps in
199 the program:
201 fn foo -> _/eax: int {
202   var x: int
203   # statement 1: store 3 in x
204   # statement 2: define a new variable 'y' in register eax and store 4 in it
205   # statement 3: add y to x, storing the result in x
206   return x
210 Again, you're encouraged to repeatedly try out your programs by running this
211 command as often as you like:
213 ./translate tutorial/task5.mu  &&  qemu-system-i386 code.img
216 The section on [integer arithmetic](https://github.com/akkartik/mu/blob/main/mu.md#integer-arithmetic)
217 shows that Mu consistently follows a few rules:
218 * Instructions that write to a register always have an output before the `<-`.
219 * Instructions that use an argument in memory always have it as the first
220   inout.
221 * Instructions that write to memory have a preposition in their name. Contrast
222   `add` to a register vs `add-to` a memory location, `subtract` from a
223   register vs `subtract-from` a memory location, and so on.
225 If you're stuck, as always, [my door is open](http://akkartik.name/contact).
226 You can also see a solution in the repository, though I won't link to it lest
227 it encourage peeking.
229 Where possible, try to store variables in registers rather than the stack. The
230 two main reasons to use the stack are:
231 * when you need lots of variables and run out of registers, and
232 * when you have types that don't fit in 32 bits.
234 ## Task 6: getting used to a few error messages
236 If you're like me, seeing an error message can feel a bit stressful. It
237 usually happens when you're trying to get somewhere, it can feel like the
238 computer is being deliberately obtrusive, there's uncertainty about what's
239 wrong.
241 Well, I'd like to share one trick I recently learned to stop fearing error
242 messages: deliberately trigger them at a time and place of your choosing, when
243 you're mentally prepared to see them. That takes the stress right out.
245 Here's the skeleton for `tutorial/task6.mu`:
248 fn main {
249   var m: int
250   var r/edx: int <- copy 0
251   # insert a single statement below
256 (Reminder: `m` here is stored somewhere in memory, while `r` is stored in
257 register `edx`. Variables in registers must always be initialized when they're
258 created. Variables in memory must never be initialized, because they're always
259 implicitly initialized to 0.)
261 Now, starting from this skeleton, type the following statements in, one at a
262 time. Your program should only ever have one more statement than the above
263 skeleton. We'll try out the following statements, one by one:
265 * `m <- copy 3`
266 * `r <- copy 3`
267 * `copy-to r, 3`
268 * `copy-to m, 3`
270 Before typing in each one, write down whether you expect an error. After
271 trying it out, compare your answer. It can also be useful to write down the
272 exact error you see, and what it means, in your own words.
274 (Also, don't forget to delete the statement you typed in before you move on to
275 trying out the next one.)
277 Making notes about error messages is an example of a more general trick called
278 a [runbook](https://en.wikipedia.org/wiki/Runbook). Runbooks are aids to
279 memory, scripts for what to do when you run into a problem. People think worse
280 in the presence of stress, and runbooks can help reduce the need for thinking
281 in the presence of stress. They're a way of programming people (your future
282 self or others) rather than computers.
284 ## Task 7: variables in registers, variables in memory (again)
286 Go back to your program in Task 5. Replace the first statement declaring
287 variable `x`:
289 var x: int
292 so it looks like this:
294 var x/edx: int <- copy 0
297 Run `translate` (or `translate_emulated`) as usual. Use your runbook from Task
298 6 to address the errors that arise.
300 ## Task 8: primitive statements vs function calls
302 Managing variables in memory vs register is one of two key skills to
303 programming in Mu. The second key skill is calling primitives (which are
304 provided by the x86 instruction set) vs functions (which are defined in terms
305 of primitives).
307 To prepare for this task, reread the very first section of the Mu reference,
308 on [functions and function calls](https://github.com/akkartik/mu/blob/main/mu.md#functions).
310 Now look at the following programs. In each case, write down whether you
311 expect translation to return any errors and why.
314 fn f a: int {
317 fn main {
318   f 0
319   var r/eax: int <- copy 3
320   f r
321   var m: int
322   f m
326 (When you're ready, try the above program out as `./translate tutorial/task8a.mu`.)
329 fn f -> _/eax: int {
330   var result/ecx: int <- copy 0
331   return result
334 fn main {
335   var x/eax: int <- f
339 (When you're ready, try the above program out as `./translate tutorial/task8b.mu`.)
343 fn f -> _/eax: int {
344   return 3
347 fn main {
348   var x/ecx: int <- f
352 (When you're ready, try the above program out as `./translate tutorial/task8c.mu`.)
354 Functions have fewer restrictions than primitives on inouts, but more
355 restrictions on outputs. Inouts can be registers, or memory, or even literals.
356 This is why the first example above is legal. Outputs, however, _must_
357 hard-code specific registers, and function calls must write their outputs to
358 matching registers. This is why the third example above is illegal.
360 One subtlety here is that we only require agreement on output registers
361 between function call and function header. We don't actually have to `return`
362 the precise register a function header specifies. The return value can even be
363 a literal integer or in memory somewhere. The `return` is really just a `copy`
364 to the appropriate register(s). This is why the second example above is legal.
366 ## Task 9: juggling registers between function calls
368 Here's a program:
371 fn f -> _/eax: int {
372   return 2
375 fn g -> _/eax: int {
376   return 3
379 fn add-f-and-g -> _/eax: int {
380   var x/eax: int <- f
381   var y/eax: int <- g
382   x <- add y
383   return x
387 What's wrong with this program? How can you fix it and pass all tests by
388 modifying just function `add-f-and-g`?
390 By convention, most functions in Mu return their results in register `eax`.
391 That creates a fair bit of contention for this register, and we often end up
392 having to move the output of a function call around to some other location to
393 free up space for the next function we need to call.
395 An alternative approach would be to distribute the load between registers so
396 that different functions use different output registers. That would reduce the
397 odds of conflict, but not eradicate them entirely. It would also add some
398 difficulty in calling functions; now you have to remember what register they
399 write their outputs to. It's unclear if the benefits of this alternative
400 outweigh the costs, so Mu follows long-established conventions in other
401 Assembly languages. I do, however, violate the `eax` convention in some cases
402 where a helper function is only narrowly useful in a single sort of
403 circumstance and registers are at a premium. See, for example, the definition
404 of the helper `_read-dithering-error` [when rendering images](http://akkartik.github.io/mu/html/511image.mu.html).
405 The leading underscore indicates that it's an internal detail of
406 `render-image`, and not really intended to be called by itself.
408 ## Task 10: operating with fractional numbers
410 All our variables so far have had type `int` (integer), but there are limits
411 to what you can do with just whole integers. For example, here's the formula
412 a visitor to the US will require to convert distances mentioned on road signs
413 from miles to kilometers:
416 distance * 1.609
419 Write a function to perform this conversion. Some starting points:
420 * Reread [the section on variables and registers](https://github.com/akkartik/mu/blob/main/mu.md#variables-registers-and-memory)
421   with special attention to the `float` type.
422 * Read [the section on fractional arithmetic](https://github.com/akkartik/mu/blob/main/mu.md#fractional-arithmetic).
423 * One wrinkle is that the x86 instruction set doesn't permit literal
424   fractional arguments. So you'll need to _create_ 1.609 somehow. See the
425   section on moving values around under [operations on simple types](https://github.com/akkartik/mu/blob/main/mu.md#operations-on-simple-types).
427 This task has four source files in the repo that reveal more and more of the
428 answer. Start from the first, and bump down if you need a hint.
429 * tutorial/task10.mu
430 * tutorial/task10-hint1.mu
431 * tutorial/task10-hint2.mu
432 * tutorial/task10-hint3.mu
434 ## Task 11: conditionally executing statements
436 Here's a fragment of Mu code:
440   compare x, 0
441   break-if->=
442   x <- copy 0
446 The combination of `compare` and `break` results in the variable `x` being
447 assigned 0 _if and only if_ its value was less than 0 at the beginning. The
448 `break` family of instructions is used to jump to the end of an enclosing `{}`
449 block if some condition is satisfied, skipping all intervening instructions.
451 To prepare for this task, read the sections in the Mu reference on
452 [`compare`](https://github.com/akkartik/mu/blob/main/mu.md#comparing-values)
453 and [branches](https://github.com/akkartik/mu/blob/main/mu.md#branches).
455 Now make the tests pass in `tutorial/task11.mu`. The goal is to implement our
456 colloquial understanding of the &ldquo;difference&rdquo; between two numbers.
457 In lay English, we say the difference between the first-place and third-place
458 runner in a race is two places. This answer doesn't depend on the order in
459 which we mention the runners; the difference between third and first is also
460 two.
462 The section on [integer arithmetic](https://github.com/akkartik/mu/blob/main/mu.md#integer-arithmetic)
463 is again worth referring to when working on this task.
465 ## Task 12: fun with graphics
467 Here's a program to draw a rectangle on screen:
470 fn main screen: (addr screen) {
471   draw-line screen, 0x100/x1 0x100/y1, 0x300/x2 0x100/y2, 3/color=green
472   draw-line screen, 0x100/x1 0x200/y1, 0x300/x2 0x200/y2, 3/color=green
473   draw-line screen, 0x100/x1 0x100/y1, 0x100/x2 0x200/y2, 3/color=green
474   draw-line screen, 0x300/x1 0x100/y1, 0x300/x2 0x200/y2, 3/color=green
478 Play around with this function a bit, commenting out some statements with a
479 leading `#` and rerunning the program. Build up a sense for how the statements
480 map to lines on screen.
482 Modify the rectangle to start at the top-left corner on screen. How about
483 other corners?
485 Notice the `screen` variable. The `main` function always has access to a
486 `screen` variable, and any function wanting to draw to the screen will need
487 this variable. Later you'll learn to create and pass _fake screens_ within
488 automated tests, so that we can maintain confidence that our graphics
489 functions work as expected.
491 The &ldquo;real&rdquo; screen on a Mu computer is sized to 1024 (0x400) pixels
492 wide and 768 (0x300) pixels tall by default. Each pixel can take on [256 colors](http://akkartik.github.io/mu/html/vga_palette.html).
493 Many other screen configurations are possible, but it'll be up to you to learn
494 how to get to them.
496 Graphics in Mu often involve literal integer constants. To help remember what
497 they mean, you can attach _comment tokens_ -- any string without whitespace --
498 to a literal integer after a `/`. For example, an argument of `1` can
499 sometimes mean the width of a line, and at other times mean a boolean with a
500 true value. Getting into the habit of including comment tokens is an easy way
501 to make your programs easier to understand.
503 Another thing to notice in this program is the commas. Commas are entirely
504 optional in Mu, and it can be handy to drop them selectively to group
505 arguments together.
507 This is a good time to skim [Mu's vocabulary of functions for pixel graphics](https://github.com/akkartik/mu/blob/main/vocabulary.md#pixel-graphics).
508 They're fun to play with. Once you want to use a specific function, look for
509 details on the arguments it expects in `signatures.mu`.
511 ## Task 13: reading input from keyboard
513 Read the section on [events](https://github.com/akkartik/mu/blob/main/vocabulary.md#events)
514 from Mu's vocabulary. Write a program to read a key from the keyboard. Mu
515 receives a keyboard object as the second argument of `main`:
518 fn main screen: (addr screen), keyboard: (addr keyboard) {
519   # edit in here {
521   # }
525 The _signature_ of `read-key` -- along with many other functions -- is in
526 [400.mu](https://github.com/akkartik/mu/blob/main/400.mu).
528 One wrinkle in this problem is that `read-key` may not actually return a key.
529 You have to keep retrying until it does. You may have already encountered the
530 list of `loop` operations in the section on [branches](https://github.com/akkartik/mu/blob/main/mu.md#branches).
531 It might be a good time to refresh your knowledge there.
533 ## Task 14: streams and scanning input from the keyboard
535 Here's a skeleton of a program for processing text typed in at a keyboard:
538 fn main screen: (addr screen), keyboard: (addr keyboard) {
539   var in-storage: (stream byte 0x80)
540   var in/esi: (addr stream byte) <- address in-storage
541   read-line-from-keyboard keyboard, in, screen, 0xf/fg 0/bg
542   {
543     var done?/eax: boolean <- stream-empty? in
544     compare done?, 0/false
545     break-if-!=
546     var g/eax: code-point-utf8 <- read-code-point-utf8 in
547     # do stuff with g here
548     loop
549   }
553 `read-line-from-keyboard` reads keystrokes from the keyboard until you press
554 the `Enter` (also called `newline`) key, and accumulates them into a _stream_
555 of bytes. The loop then repeatedly reads _code points_ from the stream, and
556 these code points are encoded in a special encoding of Unicode called UTF-8.
557 Mu doesn't yet support non-Qwerty keyboards, but support for keyboards in
558 other parts of the world should be easy to add thanks to our support for
559 UTF-8.
561 This is a good time to skim the section in the Mu reference on
562 [streams](https://github.com/akkartik/mu/blob/main/mu.md#streams), just to
563 give yourself a sense of what you can do with them. Does the above program
564 make sense now?  Feel free to experiment to make sense of it.
566 Can you modify it to print out the line a second time, after you've typed it
567 out until the `Enter` key? Can you print a space after every code point when
568 you print the line out a second time? You'll need to skim the section on
569 [printing to screen](https://github.com/akkartik/mu/blob/main/vocabulary.md#printing-to-screen)
570 from Mu's vocabulary. One common pattern: Mu programs read characters in
571 UTF-8, but print raw `code-point`s. Use `to-code-point` to decode UTF-8 and
572 get at the underlying raw `code-point`, and use `to-utf8` to encode a
573 `code-point` into a `code-point-utf8`. (This stuff is still under
574 construction; I hope to simplify it over time.)
576 ## Task 15: generating cool patterns
578 Back to drawing to screen. Here's a program that draws every pixel on `screen`
579 with a `color` equal to the value of its `x` coordinate.
582 fn main screen: (addr screen) {
583   var y/eax: int <- copy 0
584   {
585     compare y, 0x300/screen-height=768
586     break-if->=
587     var x/edx: int <- copy 0
588     {
589       compare x, 0x400/screen-width=1024
590       break-if->=
591       var color/ecx: int <- copy x
592       pixel screen x, y, color
593       x <- increment
594       loop
595     }
596     y <- increment
597     loop
598   }
602 Before you run it, form a hypothesis about what the picture will look like.
603 The screen is 1024 pixels wide, but there are only 256 colors. What are the
604 implications of these facts?
606 After you run this program, try to modify it so every pixel gets a `color`
607 equal to the sum of its `x` and `y` coordinates. Can you guess what pattern
608 will result? Play around with more complex formulae. I particularly like the
609 sum of squares of `x` and `y` coordinates. Check out the [Mandelbrot set](https://github.com/akkartik/mu/blob/main/apps/mandelbrot-silhouette.mu)
610 for a really complex example of this sort of _procedural graphics_.
612 ## Task 16: a simple app
614 We now know how to read keys from keyboard and draw on the screen. Try out
615 [tutorial/counter.mu](https://github.com/akkartik/mu/blob/main/tutorial/counter.mu)
616 which implements a simple counter app.
618 <img alt='screenshot of the counter app' src='counter.png'>
620 Now look at its code. Do all the parts make sense? Reread the extensive
621 vocabulary of functions for [drawing text to screen](https://github.com/akkartik/mu/blob/main/vocabulary.md#printing-to-screen).
625 Here's a more challenging problem. Build an app to convert celsius to
626 fahrenheit and vice versa. Two text fields, the `<Tab>` key to move the cursor
627 between them, type in either field and hit `<Enter>` to populate the other
628 field.
630 After you build it, compare your solution with [tutorial/converter.mu](https://github.com/akkartik/mu/blob/main/tutorial/converter.mu).
631 A second version breaks the program down into multiple functions, in
632 [tutorial/converter2.mu](https://github.com/akkartik/mu/blob/main/tutorial/converter.mu).
633 Can you see how the two do the same thing? Which one do you like better?
637 There's lots more programs in this repository. Look in the `apps/` directory.
638 Check out the Mu `shell/`, which persists data between runs to a separate data
639 disk. Hopefully this gives you some sense for how little software it takes to
640 build useful programs for yourself. Do you have any new ideas for programs to
641 write in Mu? [Tell me about them!](http://akkartik.name/about) I'd love to jam
642 with you.