Everything You Need to Know About Computers v0.25 ---------\ +++++++ | ! | | + + | | | + ? + ---------/ + +------ooooooooo--------- +++++++ ooooooooo + + + + + + + + -------------------------------------- 0.0 Introduction In this book, I am going to teach you everything I learned in my years of bizzare ventures into the world of computing. I am still learning, not everything here is accurate. 0.1 Zen Moment What is a computer? A computer is a machine that carries out logical operations. But what is a machine? A machine is a force motioning a body. A body is a physical structure. Therefore, a computer is any force that carries out calculations using a physical structure. Thus, our brains are computers, animals are computers, the waves moving in perfectly mechanically calculated trajectory are computers... the universe is a computer, carrying out an uncountable amount of calculations on all physical space. Just a bit of zen thinking for a good mood. 0.2 History 0.2.1 Babbage The reason why "computer" and "calculator" are synonymous in some languages is that the first "official" computer was The Differential Engine by Charles Babbage - this machine served to carry out accurate calculations of extremely large numbers. 0.2.2 UNIX Philosophy Around 1978, the UNIX system appeared and UNIX (programming) philosophy began to become apparent. The idea was to create simple programs that do only one thing and do it well; make it small, simple and portable; and make it interact well with other programs. These programs were so open to be rewritten and updated by anyone, most of them did not even have licenses. 1.0 Boolean Logic Boolean logic can be explained like this: A computer is built out of millions of tiny switches - BITS. These switches can be OFF or ON (also known as NO or YES, FALSE or TRUE, 0 or 1). You enter some INPUT into the computer, the computer will do some calculations based on the way the switches are set, and then it produces OUTPUT. ++++++++++++ -INPUT---+ COMPUTER +--- OUTPUT ++++++++++++ 1.1 Binary The reason why we can make a computer - a machine capable of calculations with numbers - out of simple 0/1 switches, is that we can write down any number only using 0s and 1s, using binary. Our counting system - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9... 10, 11, 12 Binary - 0, 1... 10, 11... 100, 101, 110, 111... In the above system, the "10" represents a 2, the "11" is a 3, the "100" is 4. Using a large system than binary would make the already complicated arranging of data even more confusing. We can read any binary number if we think of each position like this: 0 0 0 0 0 0 | | | | | | 32 16 8 4 2 1 We can read a large binary number like this: 101010 1 0 1 0 1 0 | | | | | | 32 8 2 32+8+2 = 42 A binary number with 6 digits can hold a maximum value of 63, otherwise we need a new digit. The amount of possibilities is 64 though, 0 also counts. 1 1 1 1 1 1 | | | | | | 32 16 8 4 2 1 - 32+16+8+4+2+1 = 63 1.2 AND, OR, NOT AND and OR are some of the most basic operators - statements/manipulations of the ON/OFF switches we have. These specific operator takes in two operands - two switches - and outputs one based on their function. These kinds of statements actually get used in programming languages. - 0 / 1 --- ++++++++++++ + OPERATOR +--- OUT - 0 / 1 --- ++++++++++++ AND - the output is TRUE if both statements are TRUE a | b |out| ---|---|---| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | OR - the output is TRUE if either statement is TRUE a | b |out| ===|===|===| 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | NOT - only takes one operand, the output is flipped (FALSE to TRUE, TRUE to FALSE) a |out| ===|===| 0 | 1 | 1 | 0 | We can make out any logical manipulation or calculation using AND and NOT. Even OR can be constructed from them, the following set of operators has the exact same output as OR: +++++ +++++++++++ - a ---+NOT+---+ + +++++ + + +++++ + AND +---+NOT+--- OUT +++++ + + +++++ - b ---+NOT+---+ + +++++ +++++++++++ 1.3 Black Box Abstraction I am noting these down using black box abstraction - a principle akin to the UNIX philosophy mentioned earlier. When you have some process or solution to a problem fully realised, you note it down, and you "build a box" around it. It is the BLACK box abstraction because the box is "covered" - you do not have to look inside to understand what it does (although you can), only know how to write the INPUT. In the above example of how OR could be constructed, I could wrap the entire notation in a box called "OR" and noone would have to look inside to understand the basic functionality of it. 1.4 Circuits The reason why we will be building everything out of these specific three operators is that they are extremely close to how logic in basic eletrical circuits functions. Here is a real-life electric circuit that notes the AND logic operation: / / ---o o---o o-- | | | | | | ---B-------L---- B is the battery and L is the lightbulb. Power will go through and the lightbulb will turn on only if both switches a and b (inputs) are ON, just like in our AND operation. OR circuit: / ----o o---- | | | / | |---o o---| | | | | ---B---L---- 1.4 NAND NAND is the magical "bedrock" operator - we can build any other functions with it, even AND and NOT. a | b |out| ===|===|===| 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | NOT is equal to: - a ---++++++++ + NAND +--- OUT - a ---++++++++ AND is simply a reverse of NAND, it can be applied by combining NAND and NOT. - a ---++++++++ +++++++ + NAND +---+ NOT +--- OUT - b ---++++++++ +++++++ 1.6 Composite and Advanced operators 1.6.1 Composite Operators We established that we can build any function using the NAND operator. We can also build composite operators - functions that take in more than two operands at a time. An AND operator that takes in three bits of input can be made by just putting two AND operators together: - a ---+++++++ +++++++ + AND +------+ + - b ---+++++++ + AND +--- OUT + + - c ----------------+++++++ 1.6.2 Advanced Operators We can also build XOR and NOR - the only two remaining operators possible with only two bits of input. XOR - TRUE only if one input is TRUE a | b |out| ===|===|===| 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | Can be built from NOT, AND, OR: - a ---------------+++++++ + AND +----------++++++++++ |-+++++++ + + - a ---+++++ | + OR +--- OUT +NOT+-----x--------+++++++ + + +++++ | + AND +---+ + | |-+++++++ ++++++++++ +++++ | | - b ---+NOT+-----| | +++++ | | - b --------------------| NOR - only true if neither input is true a | b |out| ===|===|===| 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | - a ---++++++ +++++ + OR +---+NOT+--- out - b ---++++++ +++++ A multiplexor is an operator that takes in two bits of data and outputs one based on a third input called "sel" - selection. If sel is 0, output is a, if sel is 1, output is b. a | b |sel|out| ===|===|===|===| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | --------------- 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | +++++++ - a ---+ MUX +--- out - b ---+ + +++++++ | | sel | A DMUX or Demultiplexors works in reverse - it takes a single input along with sel, and outputs it based on the value of sel, into one of two channels. The other channel receives 0. ++++++--- a - in ---+DMUX+ ++++++--- b | | sel | in|sel| a | b | ===|===|===|===| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | We can use this kind of operation to not only produce different operators, but different operands aswell - we can for example choose to pipe something into an AND gate if sel is 0, and an OR gate is sel is 1. 2.0 Hardware How does all this translate to something appearing on the monitor? A computer takes in some input - you pressing a letter button for example - deals with it based on the wide array of operators - then communicates with the monitor to output it. To be precise, the computer interprets which button had been pressed, and, for example, if you have notepad open, understands within its rules that it should put that letter into notepad. These rules - arrangemenets of operators within a computer - are the operating system (OS). Every computer, even without the operating system, has firmware - software that works with the computer/hardware at the closest level. One is BIOS - basic input/output system. The monitor can also have, within itself, a series of chips(firmware) that take whatever input the computer gave it, and translates it to an array of pixels, displaying each, one by one on the screen at extreme speed - in this case, it will take the same input as before, only there will now be a letter on the notepad part of the screen. Every operating system has a terminal - a blank window into which you can type commands to access different directories, open files etc. A lot of basic programs output everything into the terminal, so we will work with it a lot. 2.1 HDL An HDL - hardware description language - is used to note down the specifics of operators, like the "AND, OR, NOT" operators we saw in the previous chapter. Here is a notation of an OR operator, the way we built it in 1.2. CHIP Or { IN a, b; OUT out; PARTS: Not (in=a, out=nota); Not (in=b, out=notb); And (a=nota, b=notb, out=notaAndb); Not (in=notaAndb, out=out); } The top part notes what exactly the chip is - takes 2 inputs, produces 1 output - while the bottom shows exactly what other chips it is built out of, same thing as the diagram of the chip in 1.2. We have defined OR, and we can now use it as in the "PARTS" section of another notation, and write more complex operators like XOR and MUX, in a way that can be noted down for future use. 2.2 Programming languages While HDL is mainly used for notation, programming languages actually manipulate data within the computer, using different methods. An operating system has a compiler - a tool which translates code written in a programming language readable to us into "machine code" - the raw 0s and 1s we were manipulating at the beginning. There is also the linker - a tool which the compiler uses to link the code with the libraries. 3.0 C C is an imperative language - A barebones program in C (that does nothing) looks like this: #include int main(void) { // write commands here return 0; } Aside the "include" bit, C always begins by executing the "main" function, using parameters in the brackets next to it (in our case "void" - there are no extra parameters). "return" is always included to signal the end of a function. The double slash is used to post comments, which are readable by the programmer, but the program itself ignores completely - the "write commands here" part does not affect the program at all. Here is the same function with comments explaining what each part does: #include // include the I/O library // more libraries can be included here int main(void) { // write commands here return 0; // always the last command } Besides the double slash, sometimes comments are included in the following format: /* This is a comment. */ /* This is the next line */ Most programmers prefer the double slash. The "include" function pulls in libraries - we can think of them like the logical operators mentioned in 1.2. In our case, it is the "stdio.h" library, one of the most basic, used libraries as it allows us to take input and produce output (I/O) - understandably, this is extremely necessary. 3.1 Printf "Hello World" Printf is a notation often used to show the basic functionality of input/output of the program, it stands for "print formatted". It takes in basic text input, and puts it directly out on the terminal. This is very useful when you are testing something, you can check if a part of the program is working by making it print something. #include // include I/O library int main(void) { printf("Hello world."); return 0; } The output - the terminal will appear, noting the single line we put into printf: Hello world. There is a function that does the exact same thing but also includes a new line, "puts". There is also a function "getchar()" which will expect user input - use in case the terminal closes immediately after executing, which it does on some operating systems. 3.2 Logic Operators in C C has the exact AND, OR, and NOT operators mentioned before. && - AND || - OR ! - NOT We will declare some variables - manipulatable numbers - and test each operator. #include int main(void) { int my_variable; int my_variable2; my_variable = 10; my_variable2 = 90; printf("%d\n",my_variable); printf("%d\n",my_variable2); } %d - the position to which the variable on the right is put \n - new line We have declared two variables, one holding the value of 10 and one of 90, then we asked for their value to be output. The program will output: 10 90 Basic AND check: #include int main(void) { int input1; int input2; input1 = 0; input2 = 0; // input 0 or 1 if (input1 == 1 && input2 == 1) { printf("TRUE"); } else { printf("FALSE"); } } The "&&" is AND. OR is "||" and we can simply replace the && symbol to test it immediately. But this program only spits out "TRUE" or "FALSE", it does not actually change any number of variable for future use. In the following program, it does: #include int main(void) { int input1; int input2; int output; input1 = 0; input2 = 0; // input 0 or 1 if (input1 == 1 && input2 == 1) { printf("TRUE"); output = 1; } else { printf("FALSE"); output = 0; } } A new variable - "output" - will be assigned a value of 0 or 1 based on the value of the two inputs. Since we are not only using variables with the value of 0 and 1, there are a lot of other operands. == - equals (as seen above) != - not equal < - less than > - more than <= - less than or equals >= - more than or equals And we can do a lot more with them, like add them or increase them. The following will add the value of two variables. #include int main(void) { int input1; int input2; int output; input1 = 8; input2 = 15; // input a number output = input1+input2; printf("%d\n", output); } The output will be: 23 3.3 "FOR, WHILE" Loops LOOPS are functions that repeat until a condition is met. For example: ====================== PUT PROGRAM HERE ====================== Will output Increasing... 1 Increasing... 2 Increasing... 3 Increasing... 4 Increasing... 5 We can also make it including a WHILE loop. #include int main(void) { int input; input = 0; // input a number, best 0-10 while (input < 5) { input = input + 1; printf("Increasing..."); printf(%d\n input) } } In the FOR example, we had a fixed value of 5. WHILE loops are usually used exclusively for variables that we do not have declared ahead of time - for example, to compare two inputs. We can use functions within functions: =============== FINISH THIS =============== void timesfive (int ) { int } int main(void) { timesfive(3); put number in brackets you want multiplied by 5 } 3.4 Integer Types 3.5 Data Types string - holds some value (number / characters) array - sequence of values of same data type - ex. 33, 12, 9 struct - sequence of values of possibly different data types, values not assigned in specific order In an array, you can look at "position 3" and see what is there, or make the program evaluate them in order. You cannot with structs. (?) 3.6 Program examples 3.6.1 Randomness #include #include #include int main(void) { srand(clock()); int randomnum = rand() % 3; // produces random number 0-2 for (int i = 0; i < 5; ++i) { if (rand == 0) {printf("random!\n")} else if (rand == 1) {printf("randoooom\n")} else if (rand == 2) {printf("randome :-D\n")} } return 0; } Randomness has to be seeded - . It has to be seeded within the function it is declared. 3.7 Other Notes In a program, along a typical README and LICENSE file, you will see at least one ".c" and ".h". ".h" - a header file - is used for declarations - basically all the "prep"/setup a program does at the beginning before it gets running - this is where we declare the most important variables and such. ".c" is the main body of the program that executes everything declared within itself and within ".h". The ".c" part of the program has to declare including the header file: #include #include "library.h" 3.6.1 Other Important Commands break(); - terminates a function 3.6.2 Important Libraries stdio - standard input/output (puts, printf) stdlib stdbool - boolean numbers/types time math - math operations (sqrt - square root) musl uClibc Libraries can be built not just generally, but for any specific function, such as "smallchesslib", a library for making a chess game. 3.6.3 Bizzare Discoveries A couple strange things I need to note. You cannot print a backslash by itself as it is used to note things like new lines (\n), use a double slash - \\. Beware of this when doing ASCII :-D ================================= program that randomly prints something 5 times as you press a key then dies randommm random randOMMMe randumem ???randome:D ================================= 4.0 Lisp ++++++ ++++++++ ++++++++++ ++ O +++ O ++ ++++++++++++++ +++++++++++++ +++++++++++ +++++++++ +++++++ +++++ +++ 4.1 Basics of Lisp Lisp is an interpreted language - the input/request is calculated/done by the program immediately. Here is one of the most basic programs possible in Lisp: (+ 3 5) The output will be 8. The syntax is simple - all parts of a program are included in brackets, operator is always at the left, operands at the right. We can do many basic math operations this way. (* 3 6) Returns 18. (+ 1 5 2) Returns 8. (/ 6 2) Returns 3. You can also make layered processes with multiple brackets. (* 3 (+ 2 2)) will be evaluated to (* 3 4) and output 12 4.2 Definitions and Conditions In C, we had to declare variables for future use. We can define them in Lisp: Definition of data: (define a (* 5 5)) equals (define a 25) Usage of defined data: (+ a 12) Prints: 37 Definition of procedure: (define (square x) (* x x) equals (define square (lambda (x) (* x x))) "Lambda" means procedure. The non-lambda version has "syntactic sugar" - syntax designed to be more readable (and less machine-adjacent) Beware: (define c (25)) Typing the text below would define c as a procedure that applies "25" to nothing and would return an error. Conditions: (define (abs x) (cond ((< x 0) (- x)) ((= x 0) 0) ((> x 0) x))) equals to (define (abs x) (if (< x 0) (- x) x)) 5.0 Extra Lingo Syntactic sugar - syntax designed to be more readable (and less machine-adjacent) Bootloader - part of the OS load it during startup Unsorted a loop in C repeats until it breaks or returns something? random seed has to be declared within the loop??????