 This time we have this block of code to work with, and again we'll be pointing out all of the dependencies, and then seeing how we can resolve the hazards that arise by using no op instructions. This time I have a whole lot of stack access, so I'm referencing my stack pointer a whole lot, and I'm really updating it only in a couple places. So I have a whole lot of instructions that are dependent on that stack pointer update to more of them are down here. So all of those instructions are really dependent on the stack pointer. Most of those aren't going to produce any data hazards because they're well away from where it's actually being changed. I've also got a dependency here in the middle where we're updating s0, and then our subtract instruction wants to use that as well. Then we have one more dependency down at the end where we're updating the stack pointer. So that's also dependent on the original stack pointer change. We also have a couple of dependencies with memory. We have two cases where we're updating a memory cell, and then we're going to read that data back out later. So we actually have dependencies there as well. These dependencies won't actually turn out to produce hazards for us, but they are technically there. Some architectures this might give us trouble, but we won't have to worry about them for hours. If I'm going to use no-ops to get around the data hazards in this, I will start with my first instruction, which is the Atommediate instruction. Then I'll recognize that my store word instruction wants to use the results. It wants to use that stack pointer that we've just updated. So I'm going to need to wait two cycles. I will need two no-op instructions there, and then I can run that store word instruction. My second store word instruction also wants to use the results of that first Atommediate instruction. So I definitely need to wait two cycles before I can run that second store word instruction. Fortunately, it's been three cycles since that instruction started already, so I won't have any problems. I had to wait two cycles for the first store word, so I don't have to wait any more to run the second store word instruction. My Atommediate instruction doesn't depend on anything, so I'll be able to run that one immediately. Then my Subtract instruction depends on the results of the Atommediate instruction, so I'll have to wait two cycles there. My Load word instruction depends on two things. One is that I've updated the stack pointer, which, again, happened a long time ago. Other is that I've updated stack pointer plus zero in memory. I would store this piece of data into memory in stage four. I would also read it back out of memory in stage four, so I could actually run these two instructions back to back, and there wouldn't be any problems. Further, there's also been a huge weight between them, so, again, there isn't going to be any problems for us. We will be able to run that Load word instruction immediately. Our second Load word instruction is pretty much the same way. It depends on the stack pointer as well as having stack pointer plus four updated with the return address. Both of those have completed, so we can run Load word number two immediately. Next, we have an Atommediate instruction and then the Jump Register instruction. Atommediate instruction is dependent on our first Atommediate, which, again, has completed a long time ago. And our Jump Register instruction is dependent on our return address. So there's actually a dependency there as well. And we've had one cycle between when we've loaded that data and when we'd like to use it. So I'm going to need to add one NOOP instruction between those two. Then I can have my Jump Register instruction. So this is what this block of code would look like once we've added NOOP instructions to accommodate the data hazards that occurred due to dependencies.