 In this video we're going to walk through how we can use the stack, how we can access it, how we can manipulate it, how we can get it to do things that we're interested in. For this example, I have a kind of generic block of code, it's not going to do anything really meaningful, but it will allow us to do everything we're really interested in. I have a handful of registers, and then I've got a big block of memory. Up at the top it's got some allocated memory, something that some other function has used. And then everything else in green is unallocated memory. I have a stack pointer here telling me, I have a stack pointer here telling me where the demarcation between allocated memory and unallocated memory is. Then I've divided the memory up into word size blocks so that all of them are going to be 32 bits. All of my memory access operations this time are going to involve 32 bit objects. So this will work out really nicely, it will be relatively easy to understand what's going in where it's going in. So the first instruction I have says that I should subtract 8 from my stack pointer. So this has the effect of declaring 8 bytes of memory as allocated now. It's been allocated for me, so it's not being used by somebody else. And it's not considered unallocated memory. So this memory is useful for me. I can take this, I can do whatever I need with it. The next instruction says I should take the data in S0 and copy it to the region of memory specified by the stack pointer plus 0. So there's my stack pointer, I go up to 0 more bytes. And I copy in the 32 bits from S0. So that will fill up memory region from stack pointer to stack pointer plus 3. So the bytes stack pointer plus 0, stack pointer plus 1, stack pointer plus 2, and stack pointer plus 3 will all be used to hold that value. In this case it's 15, and we know we got it from S0. So I've written that into the memory cell. The memory cell itself only remembers the 15. But this can be useful, especially if you've got variables. Our next instruction says we should copy the data from S1 into stack pointer plus 4. So now that value of 8 goes into stack pointer plus 4, stack pointer plus 5, stack pointer plus 6, stack pointer plus 7. So those four bytes will be used to hold the value of 8. Next I have a load word instruction. The load word instruction says go to stack pointer plus 0, copy that data out, and put it over in T1. So now I have 15 as the value of T1. Next I'm going to calculate the value of T0 plus T1, and I'll stick that in T2, so we get 22 there. Now I'm going to allocate another four bytes of space on my stack. So you can see my stack pointer moved down. I've got more memory allocated for me. But this hasn't affected anything that I'd already put on the stack. But now I can store something in there. So I'm copying T2 into that newly allocated region. Next thing is an add instruction. So I'm going to add T1 plus T2, which gives me 37, and I'm overwriting S0. So S0 now has the value of 37. But the memory location that I previously stored S0 into isn't changed. It still has that original value of S0. So changing the registers directly is not going to affect what happens in memory. So again, if I do a subtraction operation, I update the value of S1. That doesn't change what I've got up here in memory. But I can change the values that I've got in memory. I can overwrite them by, say, using another store word. So now I'm writing the current value of S1 into stack pointer plus 4. So I go to the current value of stack pointer. I go up 4 bytes, and I use those 4 bytes to store the value of 14. So it's important to notice that we are using the current stack pointer, not the original stack pointer, the way we did with S1 the first time. So the load and store word instructions are going to work the same way every time. They're not going to remember anything for you. They're just always going to work on whatever data you give it. Lastly, I'm going to increment my stack pointer by 12. This has the effect of deallocating all that memory that I used. So my stack pointer is back where it started, but you'll notice all that data that I put into memory is still there. It's not going to go away just because I've deallocated that memory. I could actually go read that data right back out now. But because it's in deallocated memory, it's considered fair game for anything else that needs it. Most likely this would be another function call, but my code could decide to go back later and allocate some more memory for itself as well. One other point to make at this point is that we can allocate and deallocate memory in any size that we want. When I'm writing code, I like allocating large blocks of memory. If I know that I'm going to need to put five integers onto my stack, then I'll just make room for five integers. And then when I get to the end of my function, I'm ready to deallocate memory. I just deallocate all of the memory that my function allocated. I do that all at once. This turns out to be more efficient than the alternative. This is nice in that it's fast, it's effective. But not everybody likes this strategy. This thing is called a stack, so some people like working with it as though it was in fact a stack. So alternatively, you could decide that you really want to have push and pop operations available to you where you would allocate some memory and put some data in. Then when you want that data back, you pop that data off. In most cases, that will work just fine. But if you have to pop several things off your stack, then you may have trouble getting to some of your data that you put on there early, but some people really like using the stack metaphor here. And that will work. You certainly can use that. That is essentially the idea that we've got here, but we can also think of our stack in terms of the frames. Where each function pushes a frame on and pops that frame off when it's done. Inside the frame though, we're not too worried about how the memory is allocated and deallocated.