Welcome. So this is our second lecture of ELE 475,
Computer Architecture. And in today's lecture, we are going to be
learning about microcoded microprocessors, so these are microprocessors which allow
you to reuse components and reuse datapath components in order to make a smaller
processor. And we're going to start our review, our
first review of three reviews. And like I said before in the previous
lecture, if you are watching this lecture, and think, well, I've seen this all before
stick through the first three or three and a half lectures.
That's designed to be reviewed to get everyone on the same page for this class.
So I'm David Wentzlaff. I'm a professor here at Princeton
University in the electrical engineering department.
And let's get started talking about our second lecture on computer architecture.
So a little bit about an agenda for what today is going to be about.
We're going to start off by talking about microcoded microarchitectures, and then
we're going to transition to talk about pipelines, basic pipelines, and review of
basic pipelines. And we're going to talk about the basics
of pipelining, that we are going to talk about and, and talk about the frameworks
which we are going to need to analyze other pipelines or analyze pipelines.
Then we're going talk about structural hazards in pipelines.
So these are problems where you might need to use a resource in two different
locations in a pipeline at the same time. Then, we're going to talk about data
hazards. Data hazards are where you have one
instruction or one operation or transaction which is dependent on another
operation or instruction in your pipeline, but they're in different stages.
So you might need to somehow interlock or control or stall between the different
stages. And then we're going to talk about control
hazards. We'll probably hold off on the control
hazards depending on how far we get into today's lecture and it might end up a
little bit, in another little snippet on the end.
But in control hazard we're going to talk about when you have an instruction which
has to redirects the pipeline or change what the pipeline is doing or the
instructions slowing down the pipeline are doing, that is another form of hazard.
Okay, so let's get off start off by talking about microcoded
microarchitectures. One of the, one of the big problems is
you're going along, this is a, a problem that happened back when processors were
first being designed, and you couldn't fit a lot of the processor in either a room,
let alone, or nowadays on a, on a chip. But one of the questions that comes up is
what happens when a processor is just too large to fit in a room, or fit in a chip.
How, how do you go about solving this? And this is not a question of how do you
solve putting multiple processors on a chip or a room, but rather if you really
can't fit a whole processor in a room, so this would be if you're building your
chips out of, or you're building your, excuse me, processors out of something
like vacuum tubes or switches or, or electromechanical relays.
You have to think pretty hard about what happens if it's, your processor's too
large, how do you cut down the size? Well you can time multiplex the resources.
So that's right, you can use a resource and instead of physically building a bunch
of resources and then collecting them together instead you can build one
resource, which is in someway general purpose and then you can use that
resource, and then use it again, and use it again multiple times for one
instruction. And this is called a microcoded processor.
So let's look at a microcontrol unit, and how one of these things works.
So, in this, in this design you'll actually have, here's the control lines
which run to your processor. So these are bunch of wires they're going
to come on to your processor and are going to assert different things on AL use,
multiplexers, registers. And then you're going to have some way you
need to try this. So in a microcoded control unit you're
going to actually have a microcode address that gets decoded and lights up in a RAM
fashion a bunch of wires. And some of those are going to turn on
these control lines and they're also going to be used in this calculation of the next
state. Now, if you look at this, you can see that
this actually implements something like a small finite state machine.
But the, the one interesting thing here is that you actually have op code from the
program coming in here. And effectively what you can do is for
each instruction you are trying to execute in a program, you can cycle through a
little state machine for it, and you can have different state machines depending on
the op code that comes in here. So the op code comes in here, you might
have for instance, condition, flags or something like that, coming out your
processor. So whether the instruction's a branch,
and, whether the instruction is taking that branch or not.
And, what you can do then is, take that along with a little flip-flop here which
would keep it in some piece of state or an address.
You can actually step through, step through a little state machine, which will
do multiple things. And we'll look at this a little more
example of how, one of these microcontrol, microcontrol units will hook up to a
microcoded microprocessor, or a microcoded processor.
The last thing I wanted to get across here is, this is typically a RAM and you can
actually cycle through it multiple times, and the RAM is going to tell you where the
next micro coded instruction is. So you'll beel, basically cycling around
this loop multiple times, or maybe only one time, depending on the actual
instruction you're trying to execute. Here is the microcoded control unit, or
the microcontrol unit hooked up to a microcontrolled process, or microcoded
processor. So, we have the datapath sitting in the
middle here. And we have a bunch of wires coming out of
our control unit here, which assert different things on the data path.
For instance, are you doing subtract, are you doing add and it's going to swing
different multiplexers inside of this data path to select what operation is actually
occurring. And I wanted to contrast the
microcontroller, or the microcontrol unit with the memory where you're actually
going to store your user programs. So your user programs are gonna be stored
in a RAM structure or a randomly accessible memory structure versus a read
only memory structure. So a good example of this is, you'd have
your actual ISA instructions here like x86 or MIPS sitting in your RAM.
And up here, you're going to have microcode instructions.
So if you go back to this diagram, typically the RAM entries are called
microcode instructions. And sometimes people write little programs
that say, how do you sort of control the different lines that come out of here.
Okay, so let's put this all together and look at how we would build a Bus-based
RISC processor. So we're going build something like a MIPS
processor, which you may recall from your computer organization class.
And we're going to use a datapath where we reuse da datapath elements over time.
So we're going to time multiplex the resources.
This is not a pipeline design and it's not even a single cycle RISC design, but
instead, it is a micro coded RISC design. And we're talking about this because we
are going to contrast this with pipelining in today's lecture.
So let's, let's look at this diagram. We're going to see, that we have a
register file here, which has 32 general purpose registers, cuz we're trying to
implement MIPS, which has 32 general purpose registers.
And we also store the program counter or the instruction pointer in this register
file. So this register file actually has 33
elements, or maybe you can store it in where there, the zero register is, ors
zero register is in MIPS if you, if you try really hard cuz that's typically hard
coded to zero. So let's walk through how a instruction is
going to be executed on such a architecture.
And a couple other things to note here this is main memory.
So we're going to have to fetch our instructions from over here.
Our ALU is here and this is our instruction register.
And everything is connected together on a bus, where only one value could be driven
at a time. And that value could be broadcast over to
multiple locations. So let's start off by thinking about what
do we need to do to execute an instruction?
Well, to execute an instruction, we're going start off by fetching the program
counter for the instruction. So the microcoded control unit, is going
to assert the wires to basically say, do a read out of the register file here for the
program counter. And we know that the prog, if the program
counter's going to be selected, because the microcontrol control unit is going to
set on the register select lines here, assert the entry which we'll choose, 32
we'll say which'll select the program counter.
So the program counter, we, and this is all in one cycle right now, the program
counter is going to be asserted onto this bus and now we need to latch it somewhere
and register. So it's going to be broadcast all the way
in this bus but we actually want to take it and load it into this memory address
register here. And else, that will finish our first cycle
of a microcoded control unit processor or microcoded control unit processor.
The next cycle, this is all within one instruction, we're going to fetch the
instruction we need from the data memory or, and the instruction memory.
So then it's going to get forced onto this bus, and we're going to take it and latch
it here or register it into the instruction register.
So, at this point we fetch the instruction.
Okay? That's, that's done a fair amount so far.
The next thing we need to do is go get the actual operands.
So on the third cycle here, we are going to take the rd, we'll say, or actually
we'll take the two sources, rs1 and rs2. Now, we're going to fetch first rs1 from
our register file and latch that or register that into the A operand.
Then we're going do the same thing for rs2 on the fourth cycle.
And now we can actually do, let's say an add.
So let's say we're assuming, we are doing an add instruction here.
So now we can do the add. So we let A and B actually add.
And we need to store the result somewhere. Well, conveniently, we know we want to
store it into the destination register. So we don't have to store it into A or B,
we can actually store it back into the register file here.
So we will be asserting rd is the address, and we will be, the microcoded control
unit will be asserting register right on the register file.
Okay, so the, we've now actually done our actual operation, almost completely.
We next need to figure out how to increment the program counter.
Because we want to go fetch the next instruction.
So as we said, we didn't store the program counter anyway, anywhere here.
So we need to go re-fetch the program counter out of the registry file.
And we're going to reuse or time multiplex the ALU here.
So we're going fetch that value, put it into A, and we're going to increment it by
four. So the next cycle we'll do, let's say an
operation here, let's say the ALU has a special operation just for adding four.
Alternatively you could try to load four into the B register here.
And we're going to add four because our instruction is four bytes long.
And we're going to store that value back into the program counter.
So at this point, we've actually executed a complete one instruction.
And it takes, I think we added up something like five, six, no, I think six
or seven cycles at that point. Now, one of the things I wanted to point
out before we most off this slide, is that, depending on the instruction you're
executing, you can have variable amounts of time taken.
So for instance, if you're trying to do a branch instruction.
Branch instructions are a little bit different.
We're not going to actually just add four to the program counter.
We might need to fetch a different value into a compare, and then fetch either the
program counter or add a different value to the program counter when we go to do a
branch operation, likewise for, for jumps. And it can have different numbers of
cycles. Another good example of different numbers
of cycles is if we're going to be operating on a unary instruction, or
instruction which only has one input. So a good example of this is a, oh, let's
think, what is this example of this? This is something like a logical negation
where you just flip all the bits, in a, in a, in a value.
I don't think MIPS actually has that instruction.
Anyway, what I'm trying to get across here is, you can actually have different number
of cycles to execute instructions depending on the instruction.
So example, of something like a load instruction, would also to a lot more
cycles because you're going to have to cycle the memory unit here more times so
you have to execute instruction where you actually go and fetch the data from the
memory and then put it back in the register and maybe do some math with it
and then store it back in, into the room, the general purpose registry file.