Okay. So, we've talked about structural hazard,
or we talked about pipe lining basics. And now, we're going to go into the three
main types of hazards. Structural hazard, data hazards, and
control hazards. Let's start off by talking about
structural hazards. Okay. So,, let's we'll review structural
hazards here. So, structural hazards, as I said before,
occurs when two instructions need to use the same hardware resource at the same
time. And there's a couple of approaches on how
to resolve this problem. I mean, we can't just throw up our hands
and just stop the pipeline, or maybe that is actually kind of one of
the solutions. But, you need to somehow think really
hard about how to deal with structural hazard.
one thing you can do is you can explicitly avoid having different
instructions that would be in the pipeline at the same time, use one
structure at the same time. And you can do this by the programmer, or
maybe the compiler can do this. Next way to go about doing this is you
actually have the hardware take care of, basically all of the problems.
And, there's some complexities in actually building this.
But you want to stall the processor, or stall a portion of the processor, or
stall the dependent instructions. or just going to, you, you stall let's
say, the earlier one when you go for the contended resource.
So a good example of this is if you have one resource two things are trying to use
it, you have a priority encoder in there it's, and the priority encoder says, the
early instruction gets to use that because if you sort of invert the
priority order, you might end up with deadlocks.
And another good way to do this is you can actually duplicate the hardware
resource or you can add more ports to a memory structure which is sort of
equivalent of duplicating the hardware resource.
And this is to some extent a solution that is used pretty widely in something
like the, the Mips pipeline, the basic five stage Mips pipeline is we actually
duplicate certain resources. For instance, there's two memory arrays.
There's an instruction memory array and there's a data memory array.
And we'll look at an example where those two things are together.
But, the simple five stage mips pipeline was really designed not to have any
structural hazards. The ISA was basically designed for that
to be the case. But more complex instruction sets in
pipeline designs, you know, you might have to deal with something like a
structural hazard. And even if with the Mips ISA, if you go
to deeper pipelines, you might end up with structural hazards and, and, we'll,
we're going to talk about that now. Okay.
So the first thing we're going to talk about here is structural hazards if we
want to unify the memory. So, as I said in the five stage Mips
pipeline, you have all the hardware you need for
every stage and all the stages are basically independent.
But, let's say we were to modify this. And instead have one memory here.
And we wire out, and, and, we only have one port into this
memory. So, only one thing can access the memory
at a time. And we wire the program counter into here
to go fetch our instructions. We wire the data out up here into the
instruction register. So, it's just wired in the same place as
the instruction memory was before. And we take the, where we had the data
memory access when we want to do a load restore.
And we run those wires down here and we put a multiplexer here to share the
address [COUGH] and only one of these resources can use it as time.
Hm. Okay, well let's draw the pipeline
diagram for what happens with something, something like this
when you go to execute a load instruction we'll say, on a unified memory
architecture. So, if we take a look at this structural
hazard example where we have a unified memory, where we have the one memory here
which is replacing both our instruction memory, and our, our data memory.
We need to walk through let's use this as an example to walk
through the pipeline diagram of how instructions would flow down this, this,
this example here. So, let's start off by executing
something like a load first. [COUGH] Then, let's say we have an add,
followed by an add, followed by an add. Okay.
So, this is our first pipeline diagram here.
We're going to have the load coming down the pipe.
And it's going to execute, or it's going to enter the fetch stage. Then, it's
going to go in to the decode stage, then it's going to go in to the execute stage,
then it's going to go in to the memory stage and finally write back.
The first add comes down here and it's going to go into fetch, so you're going
to decode, it's going to go into execute, it's going in the memory stage, follow
here write back. The third add is going to come down the
pike and then go into fetch stage, decode, execute, memory, write back.
So far, it looks like a pretty idealized pipeline.
This next add, maybe we should just put an F here.
Let's think about this. Is, is this right?
Can we have an add fetching from instruction memory at the same time as a
load is accessing the memory, this unified memory that we have here?
And this is, this is the question. We have this unified memory and we are
trying to have two things accessing it at the same time.
And this is a structural hazard. We can't, we can't do this.
So instead, we're going to put a dash here and we're somehow going to install
or bubble or no op this add for a cycle. And then, we're going to use the fetch we
are going to use the instruction on memory on the subsequent cycle.
And the reason we stall the add and we don't stall the load is because this is a
earlier instruction than this. This is a later instruction.
We want the earlier instructions to finish first.
Otherwise, we might have some deadlock concerns or some deadlock problems.
So now, we fetch, we decode, we execute, we use the memory and we write back.
And you'll note here this just gets pushed out one cycle because we had to
stall here at the beginning, one cycle. [COUGH] And, this memory and this point
here is the structural hazard that we saw, that we had to resolve.
And in this case, let's say, we stalled one cycle to resolve that hazard.
Let's, so now that we've seen how to do a unified memory and what the pipeline
should look like for that let's go on to a different example here where we have a
two cycle memory. In this two cycle memory, we're going to
have stage M0 and M1. We put a pipeline register down the
middle of our memory here. But only one thing is able to use that
memory at a time. So let's, let's briefly draw the pipeline
diagram for something like like this. [SOUND] Okay.
So, the second add is going to start flowing down the pipe and it's going to
be in the fetch stage, decode, execute, M0, M1,
write back. Then, we're going to have the load.
So, you're going to go fetch, decode, execute, M0, M1, write back.
And now we're going to see a structural hazard.
We're going to have this second load here is going to fetch.
So, I'm going on to decode. [COUGH] It's then going to go into
execute. Now, here's the problem.
If we were to put M0 here, what we see is we actually have two
different instructions in time wanting to use one resource, the memory.
So we need to solve this somehow. Now, how do you go about doing this.
Well, there is different approaches and we'll talk about that in a minute. One
approach let's say, is you could actually stall the pipline here.
So, that was one of our solutions. You stall a pipeline,
so we're going to put a dash here to mean we stalled for a cycle.
And then, we're going to have M0, m1, and then write back.
And you can see that it's basically pushed this instruction back one cycle.
But this doesn't happen with other instructions.
And the other thing to note is it doesn't happen if you have something like an add
after a load here because that's going to go fetch, [SOUND] decode, execute,
[SOUND] oh, sorry. It stalls here, too.
execute, [SOUND] M0, M1,. And these can be overlapped because we're not, we don't
actually have any hazard, in this case. Because there's, there's not a load,
loads, or two things are not trying to use this memory at the same time.
So, you won't end up with a hazard there.