Simulating Real Programs
We've reached the end of our 8086 simulation work. Time to play a little!
This is the tenth video in Part 1 of the Performance-Aware Programming series. Please see the Table of Contents to quickly navigate through the rest of the course as it is updated weekly. The homework files (listing 54, and optionally 55) are available on the github.
A lightly-edited transcript of the video follows.
We now have everything we need in our simulator to write real programs. I wanted to get to this point so we could look at cycles and performance on the 8086 where it's much simpler than x64 as a foothold before we start talking about complex modern CPUs.
But before we start counting cycles, I think we should run a real program first! Let's see how much of a program we can write with the small number of instructions that we've implemented. I think you’ll be surprised.
Suppose we want to create something that sounds fairly complex, like a game renderer or image processing application. It may seem like we would never be able to do such a thing with the small handful of 8086 instructions we've implemented. But we can accomplish a lot more than you might think!
Even massive, sprawling codebases in high-level languages compile into machine code that uses a fairly small selection of CPU instructions. There may be millions of instances of those instructions, but the number of unique instruction types is quite small. And in the core operations of something like an image editing program, there's still just a few basic CPU instructions, running in a loop, operating on memory to set things like RGB pixel values in some piece of memory that represents the image.
Using conditional jumps, we now have the ability to construct loops like that, and thanks to last post’s homework, we know we can write pixel values to memory if we want to. The only thing we're really missing is a way to see what those pixel values are visually.
But it’s actually quite simple to add that ability to our simulator. All we would have to do is add the ability to take our megabyte of simulated 8086 memory and dump it to a file. If we do that, we can read the file into an application that can display raw pixel data, and see what our program “drew” into memory.
After all, the contents of the 8086 memory is just a giant array of bytes, like we saw last time. If we choose to interpret those bytes as pixel values, we can make an image. All we need to do is write a program that picks a spot in memory and an image size, then writes the correct number of RGBA bytes to fill the image with colors we choose.
If we start somewhere in memory, and imagine that we want to make an image that is 64 pixels across, we know we have 64 pixels in memory we need to fill: