Welcome to unit 1.6 in which we are going to discuss the VM emulator. The VM emulator is a very versatile and useful tool that will come to play in many stages during this course, beginning with the present module. So let me start by placing the VM emulator in the larger scheme of what we are doing. Now to remind you, our overall purpose is to translate high level programs written say int the Jack language into machine language. And in order to do it we use a two stage compilation model. So, in the first stage we compile from the high level to VM code. In the second stage we have to somehow execute this VM code on the target platform. One way to do it is to translate the VM code into machine language, and then load the binary code into the target platform. In this case, the Hack computer and execute it. And there's also a shortcut which enables you to run the VM code as-is. And you can do this using the VM emulator. So, the VM Emulator is a high-level program. It's written in Java, in our case. And you can run this VM emulator on any computer, including your own PC. And indeed if you downloaded the Nand to Tetris software suite, you have on your computer the VM emulator that I'm going to discuss throughout this unit. People use the VM emulator for various purposes. First of all it provides the most natural and simplest way to execute compiled Jack programs. And even if this program has all sorts of visual effects like bouncing balls and playing Tetris and so on, you're going to get all these goodies in the VM emulator environment. And you can also test the programs in a systematic way using supply test scripts, which is also a nice feature of this tool. And also, people use the VM emulator in order to understand the VM abstraction. If you want to single step through a VM program and observe the impact of every push and pop command and so on, on the virtual segments and the stack, the VM emulator provides a very friendly environment to do just that. And finally, the VM emulator also gives you a glimpse into how the VM abstraction is actually being hosted on the host platform. And this will become clearer as we go on in this unit. So, here is the VM emulator in all its glory. And beginning with the left hand side, we see some VM code loaded into the VM simulator environment. This is the code which presumably is now running. And we also see a set of controls that enables us to control this code, single step through it, fast forward. Increase the speed in which the code executes and so on. Here we see the output that the program presumably generates, in this case a bouncing ball. And the VM emulator is built in such a way that this pane in which the output is displayed is kind of a multipurpose window. And it can serve the user, you, as a means with which you can look into various files. Like the output file, that your script is generating, the script file, compare file. And we'll illustrate all these as we go along. Then, we can take a look at the stack and see how it changes in response to various push and pop commands. And finally, we can also look at the virtual memory segments and see how they are being affected by the VM program. There are a few more controls and features of the VM emulator that I will discuss later on. So here's an example of what we do in general with this tool. We take some piece of code, we load it into the VM emulator and then there are a few things that we have to watch for when the code is executing. First of all, we have to understand or review this VM emulator as some sort of a hands on laboratory. So, we can look at the code and see how it impacts the stack and the virtual memory segments. And by doing so, we'll understand better how the VM abstraction is working. And we can also look at the right hand side of the VM Emulator GUI. And if we take a look at this area, we'll see how the VM abstraction is actually being realized on the host platform, on the RAM of the host computer. So, we get sort of a dual view of both the abstraction and its implementation. And it's very instructive and powerful because you can really see how the virtual machine works in two different layers of interest. Now, the next topic I'd like to discuss is the notion of test script, which is central to project seven, that you will have to do in the context of this module. So, here's a test script. It's just a plain text file, typically supplied by us. And the first thing in this test script is typically a load command, which tells the simulator to load a VM file into the simulator's environment so that we can execute and test it. Now, these VM files are typically supplied by us. Or you can write files of your own, but if you want to do it you have to use an external text editor and save it with some, filename.vm. And then you can use a load command, like this one, in order to load it into the simulators environment. You can also load it interactively but here we're discussing the notion of a test script which does everything kind of batch style. The next command in a test script typically defines an output file into which the test script is going to write some values during the execution of the program. So, for now we have an empty output file. Then, typically, the supplied test scripts also load a compare file, which is supplied by us, and the compare file now looks like, different compare files look differently. Typically, it lists the names of several selected containers, like selected areas in the RAM or in the memory segments and so on. So you get the names of the containers and the current values or the values that the script expects to see during the program's execution. Now what we'll see next is some output formatting command. And the good news is that you don't really have to fully understand all the syntax of these test scripts because we provide all these test scripts. They are written in what we call TDL, Testing Description Language, it's not really part of the course and we don't have to delve into it we have enough challenges else where. So, once again we just have to understand the spirit of what's going on. And the next thing that we see in the test script is a loop that instructs the simulator to execute the program one VM command at a time. And in this particular case, in the case of the BasicTest.vm file, We have 25 instructions, so 25 iterations would be enough to carry out the execution of this code. And finally, in this particular test script, we see that we have only one output command at the end of the script. And when the simulator executes this command, it will print to the output file all the variables that were defined in the output-list command in the preamble of the script. Now, here's the deal. If the generated output file is the same as the supplied compare file, we say that the test is successful. And the simulator will give you a positive message that the test has completed successfully. If, however, there is some discrepancy, the simulation stops and you get an error message. So that's the basic idea of using a test script. Now as it turns out, because we split the development of the VM translator into two stages, project seven and project eight, in project seven, there are some missing elements that have to be dealt with. In particular, the programs that we run in project seven are not really programs, they are, you can think about them as a sequence of instructions. And what is missing in these programs or what is missing in these sequences in order to make them programs are what I call the function and return envelope. And the function and return commands later on in project eight will cause the VM implementation to initialize the various segments that the method or the function expects to use. The local segment, the argument segment, this, that and so on. So in project seven, these segments are not initialized anywhere, and therefore someone has to take care of these initializations. And we do it using the test script. So as you see we write a set of commands, I mean, once again, these test scripts are supplied to you by us. And what we did is we added batches of commands that initialize the virtual segments manually and anchors them on selected areas in the RAM. So once we execute this setup stage in the test script, the VM code will run properly. So what I'd like to do next is give you a more detailed example of the VM emulator in action. I would like to illustrate the working of the VM emulator in the context of project seven, because in this particular project, you're required to handle several VM files, and therefore I think it makes sense to see how this tool works in the context of a project that you have to to do yourself. So what we have here is my nand2tetris folder. And let me go into projects. And within projects, I select project seven. And within these two folders, I'm going to select MemoryAccess. And within MemoryAccess let us go into BasicTest. And I see that I have four files here. The first one is a compare file. The second one is a test script. The third one is VM code. And the fourth one is yet another test script. So it's interesting, why do we have two test scripts here? Well, this is something that I will explain later on. So let me bring up my VM emulator. And proceed to load the VM file that we have in front of us. So I go to BasicTest. And I see that I have a BasicTest.vm, I load it. And let's see, it looks like we have 24 commands. Actually, 25 including command number 0. So let's start executing it by single-stepping through the code. So the first command is push 10. And indeed, we see that we have 10 in the stack. So things look good. Pop local 0. Let's execute it. Oops, I got an error message. Out of segment space. Well, the problem is that in this particular VM file, we don't have function declaration command at the beginning of the code. And therefore, no one told the simulator, so to speak, that it has to allocate memory space for the virtual memory segments. The static, local, argument, and so on. And therefore we ran into this problem. So the quick and easy way to handle this challenge of anchoring the memory segments in the RAM is to use test scripts. So instead of loading the VM code, we always recommend to load instead the test script if such is available. So let's do that. And we have two test scripts here. We choose this one, the VME.tst, we load it. And it seems like nothing happened. Well, that's because we have a little bug in the GUI. If you click this pane here, you will see the test script in all its glory. And now we can begin executing it. So I'm going to single step, as I did before. So let's click Run. And we see that several commands got executed within the test script. And indeed, the test script always executes, or the simulator always executes all the test script commands up to a semicolon. So comma is considered a microstep, a semicolon is considered the end of a step. And therefore, when we did single step, we told the simulator to execute the first four commands. The first command was load BasicTest.vm, so the simulator essentially reloaded the file that already happened to be in the program pane. And it's very good that we reloaded, because normally we may want to do some debugging in the middle. So it's always good to sort of start from fresh. And then the test script defined an output file, used a certain compare file, and so on. Well, all this is not terribly important to understand, because, you know, we don't expect you to delve into the details of the code of the test script. You just have to understand the spirit of what is going on. So let me click the single step again. And we see that we executed all these commands in the first VM step. So indeed, we did a push constant 10 and we see that the stack contains 10. Very nice indeed. We'll execute another command. And we see that the command we executed was pop local 0, and indeed, local 0 now contains 10. So let me push 21 and push 22, pop argument 2. Indeed, we see that argument 2 now contains 22, very nice. Push 36, pop this 6, we see that, well, we haven't yet executed it, so let me execute it. Pop this 6, and we see that this 6 now contains 36, push 42, push 45. This stack contains 42 and 45. So things seem to be sailing smoothly so far. And at this point, if I want. I can also take a look at the host platform. And see how what I did so far is being reflected in the underlying host platform. Which happens to be the hack computer. So I'm going to shift my attention to the host RAM. And I see that the stack pointer is 258. Now, this makes sense. Because, according to the standard VM mapping on the hack platform. The stack should begin at 256. And indeed we had a command in the test script that said set SB to 256. So stack pointer was initialized to 256. And we now have two values in the stack. And therefore, the stack pointer should be 256 plus 2, which is 258. But just to make sure, I can also scroll down the RAM here. 256 should not be too far away. Indeed, here it is. And lo and behold, I now see how the stack is hosted in the host RAM. It's right here. 4245. And stack pointer, presumably. Not presumably. I know that stack pointer points at 258. So things look nice as far as the stack is concerned. And I can explore some other things. For example, it's interesting to see where the argument segment is stored. Well, ARG is 400. So let me use this binocular control here. And enter 400. And this takes me to address 400 in the RAM. And I see that what I have here is 0, 21, 22. Which is the same as what we have here. So on the left, we have the obstruct rendition of the argument segment. And on the right, we have a glimpse into how this obstruction is actually implemented on the host platform. All right. Going back to the code, I can continue to single step through it. But this becomes a little bit tedious. So I can also fast forward. And if this is not fast enough to my liking. And I can also use the slider to make it faster. Now, when we fast forward. We essentially carry out a succession of single step events. And in every one of these single steps, we carry out the test script commands up to the next semicolon. So basically, we went through this loop here. And we did 25 iterations. And 25 iterations were enough. Because in this particular program, we have only 25 instructions. Now, how do we know that the program actually did what it's supposed to be doing? Well, typically, computer programs are designed to carry out something very concrete. Like bouncing a ball on the screen. Or staging a Tetris game. Or deciding if a given number is a prime. And therefore, the testing of these programs, in many cases, is relatively straightforward. But in this particular program, and in other programs in project seven. Some of the code is rather obscure. Because it doesn't have some global purpose in mind. But rather, it is written in order to unit test specific VM operations on the stack. And on some of the memory segments. And therefore, if you want to test this program at the VM level. Then you can either follow each instruction in isolation, interactively as we did before in this demo. Or you can let the supplied test script carry out the test on its own, so to speak. And in order to do this, you run the test script until it ends. And then if you get the nice message, end of script comparison ended successfully. You can conclude that the program has passed the mandated test. Now, the logic here is that when you execute the script file. Whenever the simulator encounters an output command within the script. It compares the results of this output to the current line in the compare file. And if the output line and the compare file line are in agreement throughout the execution of the script. Then, at the end, you're going to get this nice positive comparison and its successfully message. If there is some discrepancy along the way, the simulation is going to stop. And you're going to get an error message. Now, if you want to get into the details of this process. You can go to this control here. And take a look, for example, at the output file that this particular script has generated. Now in this script, we had only one output command at the very end of the script. And indeed, we have only one line of output. And this line displays the values of some select words from the memory. That, taken together, can help you ascertain that the program has done what it was supposed to do. So we can look at the output. We can also look at the compare file. And we know that the compare file will be the same as the output. Because otherwise, we would not have gotten this nice program completion message. And once again, this is sort of the standard way to test the program using the supplied test script. So this is the end of our VM emulator demo. There are a few dozen whistles in the features of the emulator software that I decided not to illustrate. Because we don't need them at the current level. We will need them when we stop working on project eight. The next project in our Nand to Tetris journey. So to recap, the VM emulator has several purposes. First of all, it allows us to run and test high level programs or compiled Jack programs. And also, it's a hands-on lab that allows us to delve into and understand both the VM abstraction and its implementation. So I hope that you enjoyed this basic introduction to the VM Emulator. And in the next unit, we're going to talk about the VM Implementation on the Hack Platform.