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. The re'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 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 firs t.
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.
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. 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. 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 cuz that's going to go fetch, decode, execute, oh,
sorry. It stalls here, too. execute, 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.