diff --git a/example_projects.md b/example_projects.md index 2d52cab..0a1348f 100644 --- a/example_projects.md +++ b/example_projects.md @@ -1,8 +1,9 @@ ## The first program A simple example would be to print all $2^{16}$ possible colors to the screen. -We make our lives easier, by mapping each index of the screen-buffer to the color which is encoded with the index. -Here, we use the names of the opcodes instead of their numbers. +We make our lives easier, by mapping each index of the screen-buffer to the +color which is encoded with the index. Here, we use the names of the opcodes +instead of their numbers. ``` Set 501 1 0 // Write the value 1 to address 501 @@ -15,7 +16,9 @@ Skip 0 4 503 // Unless we are at the max number, go back 4 instructions Sync 0 0 0 // Sync GoTo 0 0 0 // Repeat to keep the window open ``` -We could rely on the fact that the value at index 500 starts at zero and we did not have to initialize it. + +We could rely on the fact that the value at index 500 starts at zero and we did +not have to initialize it. To build a program that we can execute, we could use python: @@ -35,6 +38,7 @@ with open("all_colors.svc16", "wb") as f: ``` Inspecting the file, we should see: + ```ansi ➜ hexyl examples/all_colors.svc16 -pv --panels 1 @@ -47,9 +51,102 @@ Inspecting the file, we should see: 02 00 00 00 04 00 f7 01 0f 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 -``` +``` When we run this, we get the following output: ![All colors](specification/colors_scaled.png) +## Designing a simple assembly language + +If we want to compile the program from the beginning, all we have to do is to +replace `Set`, `Add`, `Print` etc. with their corresponding numbers. If we then +make our python script into a command line program that reads in this code, does +the replacement and produces the binary output, we already have our first +assembler. + +### Adding variables + +Not having to remember the opcodes is an improvement, but we still have to +manually decide which memory address holds which value. This can be automated +relatively easily. + +First, we need to identify variables. This can be easily done with the criterion +that they start with a letter and are not an instruction. + +We need to know the first memory address that is not used for instructions. +Right now, this is very easily done since every line of our program takes up +four values in memory. The first variable name we see gets replaced with the +first free address. For all the following ones we check if the variable was +assigned before. If it was, we reuse that address, and if not, we reserve a new +one. + +Our program can now look like this: + +``` +Set one 1 0 +Set max_value 65535 0 +Print color color 0 +Add color one color +... + +``` + +This is already much easier to understand. + +### Adding constants + +In the first line of that example we assigned the value 1 to a variable called +"one". This is a little catastrophe. In order to get the value 1 into our +program, we needed to run an instruction at runtime and take up 5 addresses (4 +for the instruction, one for the value). + +We want to write the values of constants into our binary directly. The program +could look like this: + +``` +Print color color 0 +Add color "1" color +... + +``` + +The way this is resolved is very similar to the way the variables are assigned. +We replace every new constant with the next free address and every reappearing +constant with its known address. The only difference is that we have to write +the values of the constant to their addresses as well. + +It would be best to change the ordering of variables and constants. The +addresses for constants already hold a value when the program starts and the +addresses for variables do not. We should put the variables at the end, so the +binary file does not contain a bunch of zeros. + +### Simple replacements + +This is a good time to invent some new instructions which are expanded to the +known ones. For now, they should have a one to one mapping, meaning that each +instruction is replaced by exactly one new one. We can, however, have +instructions with fewer arguments. Examples would be: + +``` +incr variable -> Add variable "1" variable +negate variable -> Xor variable "1" variable +jump location condition -> GoTo "0" location condition // where location is not a variable + +``` + +### Labels + +As it stands, we still have to count or remember line numbers for the `Skip` and +`GoTo` instructions. One simple Idea would be to allow a label (or multiple) for +each line. + +``` +Print color color 0 +Incr color +Cmp color "65535" condition +negate condition +jump @start condition +Sync 0 0 0 +jump @start "0" +```