Hello. This is Dr Miller, and this is Episode 9.2 of Assembly.
Today we're gonna talk about pipelines, the order of execution and conditional execution
So, pipelines, or what allows a multiple instructions to be in different stages of processing all at the same time.
And this is important because things like fetching and storing are going to be much slower.
So Ram is several orders of magnitude slower than the processor in the hard drive and network, or even slower than that.
So here's some example times. So, for example, a register takes 0.4 nanoseconds to access.
Where is Ram takes over 100 nanoseconds.
So we're gonna have well over 100 clock cycles before Ram is going to be able to access something.
And then even if you pick some of the fastest SSD Zen V M E s STS those air
25,000 nanoseconds, and so again, orders of magnitude difference in all of these,
and so pipelines help us to optimize our processes.
And you can see that this is something that we've had processors have done for quite some time.
So, for example, with penny and fours and penny MD's. The number of pipeline stages they have are between
20 and 30. And so it's something that processes have been doing for quite some time.
So here's what happens when we have sort of normal execution and we don't have a pipeline, so
we can kind of see here in the diagram, we fetch an instruction, then the next cycle we decode it than we executed. And then we write the data.
Then we fetch our next instruction decode execute,
and then right back either data or flags.
And so when we have something like
pipeline ing, we can see here that while we're fetching one instruction, we do that and then we will decode that instruction at the same time will fetch the next instruction.
Then, while we are patching this instruction, we're decoding this. Instruction were executing this one.
And so, as we can see, if we look at this eight nanoseconds versus eight nanoseconds,
we can see that here. We got to instructions done. And here we ended up getting four or five, depending on if you're at 88 nanoseconds or 19 seconds
and so we can see that
there is a benefit to that where we're getting mawr instructions executed in the same amount of time if we add pipelines.
And so the thing with branching or jumping is the case we have may have
the This will cause the processor to flush its pipeline. So as it's going, if this X this instruction does a branch,
then the next instruction or all these instructions in the pipeline are going to have to be gotten rid of because they're not correct.
So what we have is we have what modern processes do, and they speculate about which branch is gonna be taken
and then they'll actually, um,
change the order of execution. Additionally,
so is there a couple things that are processes do
so for a speculative execution? Basically, we have two different types.
We have the eager where we basically try and do both branches, and then whichever one is wrong, then we undo all of those changes or don't commit those.
And then we also have predictive. So predictive
is basically the processor has a
processor within it that is trying to predict which branches taking the most often.
And then it will go ahead and do that prediction
and guess and then if it's wrong and has to backtrack. But if it's right, then it just goes through the pipeline
and it speeds up our execution
out of order. Execution.
So one of the things that process is also do is if we think about just in order processor reinfection instruction. If it's available, or if it's in,
um, on the CPU, then we continue. Otherwise, we basically have to wait
until we can retrieve that data from RAM. And so this fetch can take a long time.
And then we go ahead and execute and store the results.
But what happens is with modern processors. What they do is they determine which instructions depend on which other ones. And so if they keep track of things like what instructions that's already fetched, what stores it's done, the results of each instruction and then dependencies as to which instruction is dependent on another one.
Then basically we can do out of order execution.
And so, with out of order execution, we go ahead infection instruction. We added to the Q of things that can be executed,
Um, and then you check the dependencies. And so if one register depends on another one. Then that instruction is gonna have to wait. But if to
instructions are independent of each other than, basically you can do either one and eat or either order.
And so if you are waiting on dependencies when those have finally met, or when all the instructions that precede this instruction
that it requires have met, then we go ahead and continue,
um, executing, store the instructions.
So conditional instructions.
So it's conditional instructions that basically have the ability to execute an instruction based on flags. So let either do the instruction or not, depending on which flags are set
so often we do something like compare, and then we might move some data depending on the result of that comparison. And we've done this using jumps so compares and jumps.
But basically we are able to reduce branching and increase efficiency. If we can go ahead and do this without having to,
um, do jumps, which again are going to be inefficient as faras are processor.
So a conditional move.
So this is going to check the state of the E flags or the set of flags that we have on the processor
and it's only going to do the move. So the sea part stands for conditional and then move. And then we have the condition
and so on. Lee, move it. The flag is set and again we have the typical. We have our pneumonic. We have the destination, we have the source
and then the CC part is the condition.
So here a couple examples. There's a whole list here,
but we have conditional move above, So move if above. So
if we did a compare and then
the part on the left is greater than the part on the right,
then we'll go ahead and actually do the move from the source to the destination. Otherwise, we won't actually do that,
or you can do something like move greater than or equal to or move less than again. Any of these will only get executed if the correct flag is set for that condition, just like we did with jumps.
So here's some examples.
So we're comparing a X and EBX and then we can say conditional, move above
e d x e X, and so we can see that if this one is greater than this one, then we're going to copy its value into GDX.
And then you can see in this example we're doing vice versus we have above and then blower equal.
So then, if this one is below or equal, then we copy EBX into E. D. X, and that's only if that is condition is true.
So with these set of three instructions, this compare and then these two moves one of these moves will get executed in the other own will not.
And then here's another compare, and then maybe a below or equal. So there's some examples of conditional moves.
So today we talked about pipelines, the order of execution and then conditional execution.
Looking forward, we're gonna take our max of three numbers, and we're going to go ahead and use conditional execution for that.
So here's a quiz. Why're but jumps bad for processors
because they cause a pipeline to be flushed, which will take more time.
How do you copy data based on flags?
Use conditional instructions. For example, the sea move,
Um, and then some condition.
If you have questions, you can contact me at Miller MJ at you and Kate I e to you, and you can find me on Twitter at Milhouse 30