Now, we actually start to talk into do things and how to build superscalar
processors, things that exploit ILP, sectional parallelism, things that run at
really high clock frequency or multiple cores and advanced techniques.
So, before we start talking about superscalar, there's a piece of
nomenclature we need to introduce that sort of goes hand in hand with the data
hazard talk that we had before. But, I didn't introduce it there, I need
to introduce it now before we go into actual superscalars.
So, let's consider some example instructions here where register i,
register j, you operate r when you put it into register k.
And, we're going to look at different types of dependencies, and we are going to
name them. So, the basic dependency here is a read
after write hazard, or read after write dependency.
So, in this example here, and if, if time goes down, this operation here is going to
store into register three. And then, this instruction here is going
to read from r3. So, you need to sort of, temporally make
sure this happens before that because you need the value here.
Okay. So, we, this is, we talked about this in
our data hazards. This is the most classic data hazard here,
a read after write hazard. Let's look at something a little bit more
a little bit less intuitive. Let's look at a hazard where this
instruction here reads register one, and the next instruction writes register one.
Okay, that should be no problem. That sounds great.
Well, today, we're going to give an example of a pipeline where this is a
problem, or could potentially be a problem.
So, you know, if you do everything in order and your instructions are sort of
slowly flowing down the pipe and you're only executing one instruction at a time,
you're going to execute this, and then that, and you're going to read register
one here. And then, like, a whole lot of time later
you are going to write register one so nothing, nothing bad happens.
But, if you start to execute instructions out of order, or if you start to execute
multiple instructions at the same time, you're going to start to come into some
problems. We're going to name this a write after
read hazard. So, what that means is, we have a write
that temporally in the program order is happening after a read of that same
register. So, when we, and this is usually called a
antidependence. And we need to, we need to maintain these
when we go to execute our programs out of order and sort of throw everything into a
big bucket and try to pull out instructions.
Okay, output dependencies. This is actually something that you could
possible even think of having happen on a simple sort of, in order processor core.
If you do right back to the register file from different stages.
So, let's take an example if you have a multiplier like in your lab which is going
to write at the end of the pipe and have a very, very high leniency and then you have
a instruction like an add which is let's say, you try to write to the register file
early, you might actually write this instructions result to register three
before that instructions results. If, let's say, this instruction here is a
long leniency operation, so it could be like a multiply, and this is like an add.
So, we're going to call that a write after write dependency.
And we need to maintain the order here that this gets written first, and then
this gets written. Because if you flop those two results or,
or interchange those two results, the next thing it goes to read r3, it can get the
wrong value. So, that's, that's pretty important.
That's called an output dependence. Okay.
So, so last question, is there such a thing as a read after read dependence or a
read after read hazard? So, superscalar processors.
So far we've been limited to processors that can only get a clock per instruction
greater than or equal to one. Superscalar processors will allow you to
execute multiple instructions at the same time and will move us into a new class
here of the clock per instruction, potentially below one.
It's at least fundamentally possible. Now, there might be other things that
cause our clock per instruction to still be above one, but we can get a higher
performance by executing multiple instructions in parallel.
I want to introduce nomenclature here, that's the reciprocal of instructions per,
or clock per instruction, which is instructions per clock.
We just, we move them and rename it. Sometimes people say IPC as the reciprocal
of CPI versus CPI, clocks per instruction equals one over instructions per clock.
So, just, just be aware of that sometimes we'll be using those terms different
iInterchangeably in this class. Okay.
So, what types of superscalar processors can we talk about?
There's lots of different types. There's in order machines and out of order
machines, roughly. And, what in order machine means is the
machine or the, the processor is still trying to execute instructions in program
order. Well, you don't have to do that.
You could actually think about sort of taking apart the program and executing
them out of order as long as you're trying to sort of, preserve the different
hazards, data hazards. And, something like your Pentium
processor. So, I'm going to pass around here a
roughly Pentium [inaudible] class processor.
It's actually Intel Celeron Pentium, Pentium [inaudible] version of the Intel
Pentium Celeron, is a out of order, three wide superscalar.
So, it can execute three instructions at a time.
For instance, the, another example is the original Pentium, the old Pentium when the
original Pentium came out, that was a two wide machine.
So, it could execute two instructions at one time and was in order.
So, you can think about these different, different notions.