We are going to devote two units to discuss memory management in the Jack Operating System beginning with Memory Access. So, here's the overall operating system, and I wish to remind you that we are implementing a class called Memory. And we'll begin by explaining the needs, the solutions, the algorithms, and so on. And finally, as usual, we'll end with the implementation notes. So the Memory class features four classical operations. Peek, poke, alloc, and deAlloc. And they are classical in the sense that every operating system out there, whether it's Unix, Windows, OSX. Implements in these operations in one way or another. And typically, they also have the same names. So the Jack operating system will include an implementation of these services also, and that's the subject of this and the next unit. In this unit, we're going to talk about peek and poke only. So, why do we need peek and poke, or what is the problem to which peek and poke is the solution? Well, our programs run on some host computer, and the host computer has a host RAM. And yet, pur programs don't know how to handle the RAM, right? If you write the program in Jack, well, the program eventually accesses the RAM. Or, we should state it more accurately, the code which is generated from our program eventually accesses the RAM. But at the high level, all we know is to handle variables, objects, arrays. Fortunately, we can access the RAMusing these obstructions. Otherwise it would be a nightmare to write high-level programs. And yet someone has to create the bridge between these high-level abstractions and the bare-bone RAM. And likewise, application programs are quite fond of reading things from the keyboard and writing stuff to the screen. And they do it without paying any attention to how these operations are actually being carried out. Well we know by now that they are being carried out by the operating system. Because the operating system, once again, provides a bridge between the high-level Jack programs and the bare-bone hardware. And the screen and the keyboard in particular are implemented using memory maps which are located also in the RAM. So at the end it all boils down to turning bits on and off in this RAM unit. And that's what peek and poke are designed to do. In particular the OS provides low level services that facilitate direct access to the RAM. And then using these low level primitives the OS builds some more advanced functions, for example, readInt and printInt. Which use these primitives in order to deliver the abstractions that the high-level programmers expect to see and use. And in this unit we are going to talk about, once again, peek and poke. Peek is designed to return the value of a selected address from the RAM. So it returns a 16 bit value. And poke takes a particular address and a value, a 16 bit value and it sets the RAM in this address to the supplied value. So for example, I've picked an arbitrary address, 1903, which happens to contain the number 7. And so if I write the code let x = Memory.peek in this address, x will become seven. If I write the code, do Memory.poke, this address to -1, then this address will become 11111 16 times. Which is the binary manifestation of decimal -1 in the 2's complement method. So, that's the typical operation or the generic operation of peek and poke. And you see why they have these names. Peek allows you to literally peek into the RAM and figure out what is written in a particular address. And poke enables you to take your finger, so to speak, and poke a particular address in the RAM. And change it to some other value if you so desire. All right, so how should we implement peek and poke? Well it turns out that this is quite a fascinating question. This is our RAM which happens to be divided into all sorts of logical areas. By the hardware and software conventions that we introduced throughout the course. And we want to be able to somehow access any given address from this RAM directly. And yet we want to do it in Jack. Because our operating system is written in Jack, just like Windows is written in C++. So how can we access the host RAM from Jack? Well, let's start with a naive solution. Here's the naive solution. We create an array that we call RAM. And we initialize it to be an array of 16 bit values of 32,768 entries which is the size of the hack RAM. Well, this will not work for two related reasons. First of all the compiler, if you recall, we've done it in the previous module. The compiler will attempt to allocate this array into the heap. Because that's what compilers do. When you ask the compiler to create a new object or a new array, it will end up calling memory alloc. And memory alloc will try to put this array or object into the heap. And this will fail, obviously, because, this array is too large. It does not fit into the heap. And so this approach is doomed. And in fact, think about it. Even if you manage somehow to stick it into the heap. Still we will not be able to access the memory maps, for example. Which we have to access if you want to control the screen and the keyboard. So this will not work. But it's sometimes it's good to start with something that doesn't work because the bad solution leads you to the right solution. And this is actually what happened to us when we thought about this challenge here. So this doesn't work and here is another approach that does work. We have obviously this memory class that we are now writing. Or eventually we will use it to implement all the algorithms that we present here. And here's what we can do. We can create a static array at the memory class level which we call RAM. We could call it any name we want but RAM makes perfect sense here. And we are going to create this array in the init function of memory. Remember that some OS classes, I haven't said it before, but maybe it's the first time I'm saying it. Some OS classes have init functions, which are not exposed to the users of these classes. And yet the classes may use them for all sorts of internal accounting and bookkeeping, so to speak, and other purposes. So, in the int function, we can do the following exotic assignment. We can say let ram = 0. Now, this is a very strange statement, because think about it. RAM is an array. And you don't expect to access arrays by using their name, right? Normally you access arrays by using some index to access. And here, we treat RAM as a variable, and we just set it to 0. Well it turns out that that's exactly what we want. Because if we set RAM to zero, then we're going to get complete access to the entire RAM. Because think about it. Anywhere in the program from now on, if we say let ram[addr] = something. Then if addr is some value between 0 and 32,767, it will place val exactly where we want. Why? Because if we access RAM i, according to the rules of the game, we're going to access the RAM location zero plus i. Because zero happens to be the base address of this array. So, this ingenious hack that you see here is going to give me complete control of the host RAM from the symbolic high level language. Now, why does this hack work? It works, because Jack is a weakly typed language. And the Jack compiler is very forgiving. And the Jack compiler doesn't care if you say let ram = 0 even if RAM is an array. In some other languages that the compiler will flow an error right here and you won't be able to do it. But in Jack you can do it. And by doing this you gain this lovely trap door into the RAM. And obviously if the programmer doesn't know what he or she is doing they can also destroy the computer now. Because now that they have complete access to the RAM, they can mess up with a stack. They can mess up with a heap and so on and so forth. So such is the power of system programmers, programmers who write system software. And obviously we are writing an operating system. So the programmers should know what they're doing. And therefore this hack is perfectly acceptable. And you need such hacks when you write an operating system in some high level language like C++. All right, so, to sum up we know how to create this RAM array which I proposed in the previous slide. And so I do it in my using my init function. And then I still have to implement peek and poke. But I would argue that now that we have this RAM array implementing peek and poke becomes a piece of cake. It's nothing, it's one or two statements and you got it implemented. So you can think about it yourself and there's no need for me to give you the exact solution. And so we know how to handle and implement peek and poke. So to remind you, we are working on the Memory class. And now that we can peek and poke we can move on to talk about alloc and deAlloc. And that's what we'll do in the next unit.