So in the last two weeks, we've built an AMU and memory hierarchy. And basically we're at the state we can just combine them and build a computer. But we're going to postpone that to next week. And this week, we're going to actually look at the computer that we want to build from a user's point of view. Study what can we do with the computers that we're going to be. What exactly is the specification of the computer we're going to build. And then, only after we've looked into it, played with it, we're actually going to build it the next week. So why do we need to do that? Well, basically because a computer is a complicated thing. It can do lots of things. When you think about it, this is really amazing. Most machines that we have in the world do one thing. Your washing machine only washes clothes, it can not cook spaghetti. On the other hand, a computer, and for that meaning a smartphone is a computer. Can do lots of different things. It can do word processing, you can play games on it, you can talk with other people, it can show you videos. There are an enormous amount of stuff that the same computer does. So how's it possible that we can do all these different things with a single hardware, with a single machine? The basic idea here is that of universality. The origins of this idea were theoretical models considered by Alan Turing in the early 19th and 20th century. He tried to formalize the notion of a computing machine, and defined a theoretical model, a Turing machine. That actually tries to capture the essence of what can be computed. And then, he noted this amazing phenomena. Although there are many different computing machines, many different Turing machines, in his model, there was a single one of them that could actually act like all of them, given the correct program, could simulate all of them, and that is called the Universal Turing Machine. That was the first time we have this amazing idea of one machine acting as a huge amount of all machines. In fact, it can act as anything at any computing machine. The same idea actually was turned into practice by von Neumann, who actually build the first serious architecture of a general computing machine. Where he noticed that where the centerpiece of his architecture, was the fact that we had the stored program computer. We can put the program software inside the hardware, and then it can act in a way that according to the software that we put there. Different programs create different operations, different functionality. And in this way, we actually have the real computer for the first time that could perform many different functions and run many different programs. And that secret is still with us today, to date, and we don't even notice how remarkable it is that our single machine can do all these many different things. So let's look slightly more carefully, how does this actually work? So we have our computer. Inside the computer we know we're going to have some central processing unit. We know we're going to have some memory. It's going to read some input to produce some output. But inside that memory is going to be a program that is going to tell the computer what to do. Well, the hardware is fixed. That program, the software, can change. And as a program, the software changes, the computer will do different things. So let's see how does the hardware, the single hardware, static hardware perform many things according to the program? Well, the program had a sequence of instructions. Each one of them is going to be coded in binary and our hardware is simply go instruction by instruction and execute it. Now, different sets of instructions, different sequences of instructions will just cause our hardware to produce completely different things. And when we take the whole sequence, the whole program, the whole sequence of instructions together, we get the functionality of the program, which can be completely dependent on what there was written there on the program itself. So now, let's look at the different elements that we will need to look at more carefully, which we will do in the next unit. That together causes the hardware to do what the program want it to do. The first thing is how are we going to specify the instructions? Our program is going to be composed of a sequence of instructions. What exactly does instruction tell the computer to do? That's one element. The other element is how do we know which instruction to perform at any given stage and time? Suppose we are now in instruction 74. It makes sense that the next instruction we will do is 75. But sometimes we'll need to change the order, maybe to do some kind of loops, or to do things conditionally. That's the second kind of element that we need to be able to, the software needs to be able to control the operation of the hardware. The third element which is really important is that we're going to have to tell the hardware what to operate on. Even if the hardware know needs now to add two numbers, we have to tell it the software has to tell the hardware how exactly where exactly will it get these two values that it needs to add, and where should it put the result. So these are the three basic elements if you wish that every Machine Language, every way that the hardware allows the software to tell it what to do needs to specify. And we'll talk a little bit about possibility, then in what kind of options are there for each one of these three possibilities made of. Now, the point is once we have this machine language, this is what the hardware allows the software to perform. Now, this machine language specification is really a programming language, but it's a terrible programming language. It's really convenient for the hardware. It allows specifying anything you want to do to the hardware, but it's really not convenient for human beings. So in reality human beings never program or almost never program exactly in machine language but they rather or program in what's called the high level programming language. A language that was designed for humans to be able to easily write what they want to do. And then, there are automatic programs called compilers which translate that into the machine language into the software which actually tells the hardware what to do when it runs it. And thus, usually we do not worry too much about the machine language because we as human programmers don't actually use it. However, from the computer's point of view, this is really what runs. Always only machine language programs run and any other programs that runs was really translated in some way, to this machine language form of living which is what exactly it tells the hardware what to do. Even though normally people do not write machine language, in this course where we are actually dealing with the hardware that is running the machine and the software that operates above it and because of it we're really learning this machine language in order to understand how to build a computer. We're going to have to deal directly with a machine language. And there are some other situations where people deal directly with machine language. For example, if they really want to have highly optimized code for very specific task, in this case, and in our course, we will need to make a working with a machine language slightly easier, and there are two things are normally done when working with machine language which makes things easier. The first thing is, instructions in machine language are always sequences of bits that keep all information in the computer. This is terrible because it's very difficult to look at the instruction 0111110 and see what it's supposed to be. But in reality, there is some way this instruction codes something in a computer and usually it codes something that we can understand. For example, it could be that the first part of this sequence of bits really codes ADD Edition. In that case, when we talk about this kind of instruction, it would be more convenient to talk about the numeric form of this instruction and simply say add instead of 01110, or whatever the code is. Similarly, part of the instruction may code a specific thing. For example, perhaps the second part of the instruction codes is a register that we want to use, whatever that means for now. In this case, again, we can write R2, which makes sense to humans somehow, implying the second register rather than the sequence of bits which really codes this too in some way depending on the machine language. So instead of talking about this sequence of bits which makes no sense to humans, we're going to say, we're going to think that what's really written there is the command ADD R3 to R2. And then, we're going to specify exactly what that means to our computer. And this is exactly equivalent to talking about the earlier sequence of bits as we'll just make things easier for us. Now, there are two ways to interpret it. The simplest way, and this is the way I prefer looking at it. The beginning at this stage.is simply that the syntactic form, the nice form, does not exist anywhere it's just the way we're talking about the real bits that exist in a computer. That's the first thing. So when we, I, say add I really mean 01110, or whatever the machine language specifies. The second interpretation goes as one line one step closer and looks at the following thing. Well, sometimes we do one too a code and machine language. And why not allows to use human to actually specify right things in this in tactic form and this was called assemble language form. And then, we can translate to the based. Very easily. This is what in a program called an Assembler does and you will actually need to build this Assembler in the sixth week. So that's a second interpretation that we will have where we actually, there is a program that allows you to write this machine language not directly as bits but in the slightly nicer assembly language format. While we're at it, making things a little bit easier, to actually write programs in machine language for the rare cases that we need to do that, including this course. Then, there's another thing that we get for free, and which is called symbols. A lot of times, in our machine language program, we will try need to access memory locations. For example, there could be a command that tells ADD 1 to memory location 129. Now, the point is for the programmer writing that, it's not really important that we actually talk about machine location and memory location 129. What you really have in mind our programmer is, that we're going to keep some kind of index in that machine location, in that memory location. So for the programmer this could have been instead you kept the program at memory location 250 or any other memory location. The important point was that every time that I'm talking, that I use this value I go to the same memory location. In this situation, we might as well, translate allows the user to write some kind of symbolic symbol, some kind of name for that memory location, let's say you call it index. It automatically lets our assembler, that already is providing us with some convenience, allows the assembler to actually translate the word index Into some free memory location, for example 129. Again, this will allow us to write programs in easier ways to humans, that looks easier ways to humans, without changing everything in reality. Whenever you see Index that really just means some memory location which is fixed. Every time we've used the same memory location whenever we talk about index. So this finishes the overview about the idea of machine languages. And what we're going to do in the next unit is actually talk a little bit about specifics of machine languages. What kind of things do we have in them, what kind of elements are they composed of. And once we have that basically background, that perspective, on what kind of machine languages, what kind of things we do in machine languages, then we'll actually start talking about the machine language of the computer that you'll build in this course, the hack computer.