1
00:00:03,360 --> 00:00:09,840
And let's start taking about exceptions
and interrupts.

2
00:00:10,280 --> 00:00:13,503
And then we're going to start talking
about superscalar two.

3
00:00:13,503 --> 00:00:16,414
So we'll start talking about out of order
superscalars.

4
00:00:16,414 --> 00:00:20,209
So how do you actually start to execute
instructions when they're not in

5
00:00:20,209 --> 00:00:23,380
programmatic order?
And when you first hear about this, you're

6
00:00:23,380 --> 00:00:27,435
gonna say, well how is that possible?
You know, you shouldn't be able to execute

7
00:00:27,435 --> 00:00:30,606
instructions out of order.
But it's very, it's relatively easy.

8
00:00:30,606 --> 00:00:33,570
You can actually, just, you know, execute
them out of order.

9
00:00:33,570 --> 00:00:36,845
Maybe you want to commit them in order.
That may even be optional.

10
00:00:36,845 --> 00:00:39,860
But let's, let's all start off by talking
about interrupts.

11
00:00:39,860 --> 00:00:45,111
So what's, what's an interrupt?
So an interrupt is typically some external

12
00:00:45,111 --> 00:00:49,903
or internal event that happens.
And it may be synchronous to an

13
00:00:49,903 --> 00:00:54,696
instruction or it may just be some
external thing that happens.

14
00:00:54,696 --> 00:01:00,706
That is going to redirect your control
flow somewhere else for a little bit of

15
00:01:00,706 --> 00:01:06,640
time and then it will come back to the
instruction that you were asked before.

16
00:01:07,220 --> 00:01:11,371
So here's our program.
It's executing, happily executing

17
00:01:11,371 --> 00:01:15,446
structure mean.
I - one, then it's going to execute

18
00:01:15,446 --> 00:01:19,026
instruction i.
Instruction i doesn't actually commit

19
00:01:19,026 --> 00:01:23,607
instead we vector over to interrupt
handler which is also some sequence of

20
00:01:23,607 --> 00:01:27,761
instructions that process some problem
let's say with instruction i.

21
00:01:27,761 --> 00:01:32,770
And then when it's done it'll come back,
re-execute instruction one, or instruction

22
00:01:32,770 --> 00:01:35,213
i.
Maybe, maybe not, we'll see why there's

23
00:01:35,213 --> 00:01:40,284
some cases that you may not actually go to
re-execute this instruction, if it had a

24
00:01:40,284 --> 00:01:42,300
fatal fault.
And then continue on.

25
00:01:43,180 --> 00:01:47,314
Typically, I wanted to point out that, a
lot of times, this is done, sort of, for

26
00:01:47,314 --> 00:01:51,861
system level code, or operating system
level code or a hypervisor level code that

27
00:01:51,861 --> 00:01:55,324
you'll jump someplace else.
So, a good example of this is a timer

28
00:01:55,324 --> 00:01:57,236
interrupt on a processor.
It goes off.

29
00:01:57,236 --> 00:02:01,112
It'll re-vector you to someplace else
where you have to sort of update the

30
00:02:01,112 --> 00:02:05,556
internal time of the machine and then, you
go back to the instruction sequence that

31
00:02:05,556 --> 00:02:10,860
you were executing before.
So let's, let's look at some of these

32
00:02:10,860 --> 00:02:11,720
causes.
So.

33
00:02:12,080 --> 00:02:17,832
We'll name the, first set of interrupts
here asynchronous interrupts, or, some

34
00:02:17,832 --> 00:02:22,855
people call these excep, external events
or external interrupts.

35
00:02:23,438 --> 00:02:28,899
And, some good examples, as I said before,
are, devices cause interrupts.

36
00:02:28,899 --> 00:02:34,432
So something like the programmable
interrupt timer on, X86 processor will

37
00:02:34,432 --> 00:02:39,893
cause a timer tick every once in a while,
or every 100 times a second, is, is

38
00:02:39,893 --> 00:02:45,171
pretty, you probable other devices,
You know, your network card gets a packet

39
00:02:45,171 --> 00:02:48,435
in on it.
And the packet needs to be processed, so

40
00:02:48,435 --> 00:02:52,767
it needs to be read of the network and be
put into ram somewhere.

41
00:02:52,966 --> 00:02:56,564
Hardware failures.
So things like EEC memory errors.

42
00:02:56,564 --> 00:03:02,162
So its error correcting code memory errors
in your main memory will sometimes cause

43
00:03:02,361 --> 00:03:05,960
interrupts to happen or asynchronous
events to happen.

44
00:03:05,960 --> 00:03:09,893
Synchronous things sometimes people call
these exceptions or traps.

45
00:03:09,893 --> 00:03:13,657
I'm actually calling all of these
interrupts because from a naming

46
00:03:13,657 --> 00:03:17,534
perspective you read different
architectural manuals they all rename

47
00:03:17,534 --> 00:03:22,142
these things slightly different and there
is no sort of common utilization of the

48
00:03:22,142 --> 00:03:25,007
terms.
But if you're, you're using something like

49
00:03:25,007 --> 00:03:29,278
x86 a synchronis interrupt is usually
called either a trap or an exception.

50
00:03:29,446 --> 00:03:33,380
But that is not common across all other
architectures are not x86.

51
00:03:33,380 --> 00:03:39,089
So some good examples of this is if you,
try to execute an instruction, which is

52
00:03:39,089 --> 00:03:44,094
not in the ISA manual.
It's a garbley, gobbledygook of bits on,

53
00:03:44,094 --> 00:03:47,984
on the disc.
So it was an error code, effectively, or

54
00:03:47,984 --> 00:03:53,400
some non-valid instruction, you get an
illegal instruction, exception.

55
00:03:53,660 --> 00:03:56,952
Or if you're trying to execute, let's say
an operating system-level instruction.

56
00:03:56,952 --> 00:04:00,202
We haven't talked about this in great
detail, we'll touch on this later in the

57
00:04:00,202 --> 00:04:02,036
course.
But if you're trying to execute some

58
00:04:02,036 --> 00:04:05,369
instruction that only the operating system
should be able to execute but you're

59
00:04:05,369 --> 00:04:09,529
executing it from your user program.
Then, you're trying to execute something

60
00:04:09,529 --> 00:04:13,985
like a privilege instruction.
That's a good way to have this happen.

61
00:04:14,184 --> 00:04:18,174
Earth medic overflow.
Some architectures have it when the,

62
00:04:18,373 --> 00:04:23,560
precision of your numbers falls outside
the scope of what you can actually

63
00:04:23,760 --> 00:04:28,415
accurately represent, you'll get an
overflow exception, or an underflow

64
00:04:28,415 --> 00:04:32,656
exception.
Similar sorts of things can happen in a

65
00:04:32,656 --> 00:04:36,289
floating point unit.
So, great example of this is if you end up

66
00:04:36,289 --> 00:04:41,041
with what are called denormalized numbers,
so in floating point numbers this means

67
00:04:41,041 --> 00:04:45,681
you basically have also lost precision in
your floating point unit, so you, you fall

68
00:04:45,681 --> 00:04:50,153
out of the range of numbers that they can
represent very well, and you end up in

69
00:04:50,153 --> 00:04:53,171
this other space that are called
denormalized numbers.

70
00:04:53,171 --> 00:04:57,308
You get an exception usually.
Sometimes other sorts of things that fall

71
00:04:57,308 --> 00:04:59,880
into this case are things like divide by
zero.

72
00:04:59,880 --> 00:05:02,859
You try to divide by zero, you'll
sometimes get exceptions.

73
00:05:03,013 --> 00:05:06,300
And you can do that.
That's a great way, if you on your x86, if

74
00:05:06,300 --> 00:05:09,280
you guys want to write a program,
Write a simple C program,

75
00:05:09,280 --> 00:05:11,077
Take some number,
Divide it by zero.

76
00:05:11,077 --> 00:05:13,851
And then build a number program.
You'll get a printout.

77
00:05:13,851 --> 00:05:16,420
The operating system will, you'll get an
exception.

78
00:05:16,420 --> 00:05:18,628
The OS will print out divide by zero
fault.

79
00:05:18,628 --> 00:05:21,300
And the program will stop.
It will kill your program.

80
00:05:22,116 --> 00:05:26,301
Unaligned memory.
Some architectures don't allow you to

81
00:05:26,301 --> 00:05:30,487
access memory in a unaligned manner.
Some architectures do.

82
00:05:30,703 --> 00:05:35,610
So something like MIPS, the MIPS
instruction set, if you go to try to

83
00:05:35,610 --> 00:05:41,022
execute a unaligned instruction sequence
or unaligned load, will say, on the

84
00:05:41,022 --> 00:05:46,362
earlier versions of MIPS, you'll actually
get a unaligned memory access.

85
00:05:46,362 --> 00:05:49,898
Later, actually, later MIPS have it as a
option.

86
00:05:49,898 --> 00:05:54,300
You can either have a, have it take a trap
or not take a trap.

87
00:05:54,900 --> 00:05:59,242
Common thing page faults.
So we talk about paging later in this

88
00:05:59,242 --> 00:06:02,325
course.
But, if you go try to access some piece of

89
00:06:02,325 --> 00:06:05,346
memory and the memory's not mapped in
correctly.

90
00:06:05,535 --> 00:06:09,688
So you, you just can't, the machine
physically can't go find memory.

91
00:06:09,688 --> 00:06:13,638
You'll take a, a trap.
And then finally, the things like system

92
00:06:13,638 --> 00:06:17,732
calls or interrupts on x86.
There's an instruction called int, which

93
00:06:17,732 --> 00:06:20,483
actually causes a, just an interrupt to
occur.

94
00:06:20,483 --> 00:06:25,005
And then it takes as a parameter a number.
So that's how system calls have

95
00:06:25,005 --> 00:06:29,344
traditionally worked on x86.
They later replaced it with actually, an

96
00:06:29,344 --> 00:06:34,539
instruction called sys enter which, does a
similar sort of thing with a little bit

97
00:06:34,539 --> 00:06:39,388
cleaner semantics.
So I think we, oh actually there's one

98
00:06:39,388 --> 00:06:43,250
point I wanted to talk about asynchronous
interrupts.

99
00:06:43,250 --> 00:06:48,860
With asynchronous interrupts, it's hard to
know when to deliver the interrupt.

100
00:06:48,860 --> 00:06:51,446
Cuz it's not pegged to a specific
instruction.

101
00:06:51,446 --> 00:06:55,487
If the instructions are going down the
pipeline, you don't necessarily know

102
00:06:55,487 --> 00:06:58,989
whether to attack it to the first
instruction that's in the pipe.

103
00:06:58,989 --> 00:07:03,084
I think it's at the sort of a fetch stage.
I think it's at the execute stage.

104
00:07:03,084 --> 00:07:07,125
I think it's at the write back stage.
So that's, that's a, that's a challenge.

105
00:07:07,125 --> 00:07:11,112
Another important thing to think about
with, asynchronous interrupts is,

106
00:07:11,112 --> 00:07:13,860
sometimes multiple of them go off at the
same time.

107
00:07:13,860 --> 00:07:17,039
So let's say your timer interrupt goes off
at, at, time t0.

108
00:07:16,931 --> 00:07:21,134
= zero, your, network card gets a packet
in and someone hits the keyboard exactly

109
00:07:21,134 --> 00:07:23,928
at the same time.
Well, which, which should happen?

110
00:07:23,928 --> 00:07:28,797
Which should you actually go handle?
Typically machines have a prioritized

111
00:07:28,797 --> 00:07:33,187
inner-request mechanism.
So there would be some sort of priority

112
00:07:33,187 --> 00:07:37,447
encoder there which will determine which
is the highest priority.

113
00:07:37,447 --> 00:07:42,756
Some of them, some machines will actually
have re-programmable priority interrupt

114
00:07:42,953 --> 00:07:48,327
encoders effectively which will allow you,
allow the system software, the operating

115
00:07:48,327 --> 00:07:53,242
system to decide what is the highest
priority interrupt to go take in that

116
00:07:53,242 --> 00:07:56,480
case.
Sometimes machines will just sort of make

117
00:07:56,480 --> 00:08:01,718
a decision, or the objects of the, of the
machine will sort of make a decision, and

118
00:08:01,718 --> 00:08:06,762
say these classes of interrupts are not
ver, or asynchronous interrupts are not

119
00:08:06,762 --> 00:08:12,129
very easy to handle so we'll sort of put
those in these of low priority bucket, and

120
00:08:12,129 --> 00:08:17,496
then some small set you'll actually be
alter sort of re, re-prioritize if you

121
00:08:17,496 --> 00:08:18,627
will.
Oh.

122
00:08:18,627 --> 00:08:21,069
Oh, yeah.
So, I wanted to talk about this.

123
00:08:21,069 --> 00:08:25,701
What actually happens, when you take a
interrupt, from a hardware mechanism

124
00:08:25,701 --> 00:08:29,019
perspective.
So the, this is a very idealized view, but

125
00:08:29,019 --> 00:08:33,088
from a mechanical perspective things need
to happen in a machine.

126
00:08:33,088 --> 00:08:35,842
There's some state that needs to be
updated.

127
00:08:35,842 --> 00:08:40,913
The first thing that needs to happen is,
you should basically stop the program at

128
00:08:40,913 --> 00:08:45,855
some point.
And you should try to save the program

129
00:08:45,855 --> 00:08:50,247
counter somewhere.
Cuz if we want to come back to, let's say,

130
00:08:50,247 --> 00:08:55,157
the instruction that took the interrupt,
We need to know where to come back to.

131
00:08:55,157 --> 00:08:59,690
But we're going to go and execute some
other piece of code in the meantime.

132
00:08:59,690 --> 00:09:02,963
So our, we can't just save it in the
program counter.

133
00:09:02,963 --> 00:09:06,804
We need to save it off.
And that's typically called either an

134
00:09:06,804 --> 00:09:10,329
exceptional PC.
So EPC that's, what its called on, on a

135
00:09:10,329 --> 00:09:14,169
MIPS, MIPS processor.
On x86, I'm trying to remember what it

136
00:09:14,169 --> 00:09:17,128
does.
I think it actually gets, pushed onto a

137
00:09:17,128 --> 00:09:20,339
systems stack.
So it gets put into memory somewhere.

138
00:09:20,528 --> 00:09:25,795
And if you had something like MIPS, one of
the tricky things here is all of your

139
00:09:25,795 --> 00:09:28,494
registers.
Are still live from the previous

140
00:09:28,494 --> 00:09:32,559
instruction sequence here.
So all of a sudden you, you jump into a

141
00:09:32,559 --> 00:09:37,063
new piece of code and all of your
instructions are still, or all of your

142
00:09:37,063 --> 00:09:41,004
registers are still live,
They have values you can't throw away.

143
00:09:41,004 --> 00:09:44,495
And you're in the interrupt exception
handler.

144
00:09:44,495 --> 00:09:47,629
What do you do?
Well there's, there's different,

145
00:09:47,999 --> 00:09:50,586
mechanisms to this, to, to have this
happen.

146
00:09:50,770 --> 00:09:55,760
Some architectures, something like MIPS
actually reserves two registers that are

147
00:09:55,760 --> 00:09:58,593
only allowed to be used by interrupt
handlers.

148
00:09:58,593 --> 00:10:01,920
This is actually a pretty poor solution in
my opinion.

149
00:10:02,105 --> 00:10:07,058
So they, they save off two registers.
I believe it is, it's somewhere high, it's

150
00:10:07,058 --> 00:10:11,268
like, maybe like 28 and 29.
Registers 28 and 29, are not allowed to be

151
00:10:11,268 --> 00:10:16,283
used by the, basically operating system,
or the user code and it's only used by

152
00:10:16,283 --> 00:10:20,060
interrupt handlers, in the operating
system to save off state.

153
00:10:20,060 --> 00:10:25,494
And what happens in that case is you could
use those registers to basically take the

154
00:10:25,494 --> 00:10:28,947
other registers,
Compute some addresses and do a store.

155
00:10:28,947 --> 00:10:33,934
Cuz if you recall on, on MIPS, you need to
have an address to do the store to.

156
00:10:33,934 --> 00:10:38,985
So you compose the address into, let's
say, register 28, and then use that as the

157
00:10:38,985 --> 00:10:42,374
store address.
And you can store off all of the other

158
00:10:42,374 --> 00:10:46,821
registers into memory somewhere.
And then you can unwind that back when

159
00:10:46,821 --> 00:10:49,910
you're, when you're going to return from
the interrupt.

160
00:10:49,910 --> 00:10:54,910
So it's a, a complicated dance.
Something like x86, there is some power

161
00:10:54,910 --> 00:11:00,665
mechanisms they are which actually take it
and take a lot of your registers and put

162
00:11:00,665 --> 00:11:06,125
them on to a in memory stock for you.
So, it's typically, well it's either a

163
00:11:06,125 --> 00:11:11,220
push A which is, push, pushes all of the
register state onto the stack and, and pop

164
00:11:11,220 --> 00:11:14,333
A which pops it off.
It is not actually required though.

165
00:11:14,333 --> 00:11:19,145
There's other, some operating systems
don't actually do push A and pop A, better

166
00:11:19,145 --> 00:11:23,334
operating systems, or more modern
operating system will actually only save

167
00:11:23,334 --> 00:11:27,080
off what is strictly needed.
That's something, something to think

168
00:11:27,080 --> 00:11:29,480
about.
One other important thing here.

169
00:11:29,480 --> 00:11:33,807
Typically when an interrupt occurs, you
probably want to mask other interrupts

170
00:11:33,807 --> 00:11:37,401
from happening.
So this is, this is a really hard problem

171
00:11:37,401 --> 00:11:40,730
to solve, is you have interrupts inside
the interrupt handler.

172
00:11:40,730 --> 00:11:43,394
Ooh.
Yeah, that doesn't sound like a, like a

173
00:11:43,394 --> 00:11:45,931
happy day for, for anyone.
Cuz what if you're in interrupt handle and

174
00:11:46,692 --> 00:11:50,689
another external interrupt comes in?
What do you, what do you do?

175
00:11:50,689 --> 00:11:55,003
You can't save the exceptional PC into the
exceptional PC state now.

176
00:11:55,003 --> 00:11:59,316
Because you've already saved the, the old
program counter into there.

177
00:11:59,316 --> 00:12:02,425
You can't take that second interrupt
inside that.

178
00:12:02,425 --> 00:12:05,977
So you can't necessarily nest interrupts
very easily.

179
00:12:05,977 --> 00:12:10,735
So what, what people do for this is, one
solution, actually, is to take the

180
00:12:10,735 --> 00:12:13,780
exceptional PC, and put it into memory
somewhere.

181
00:12:13,780 --> 00:12:17,287
And once you've done that,
Then you can turn interrupts back on

182
00:12:17,287 --> 00:12:20,296
inside the interpender.
You can take more interrupts inside the

183
00:12:20,296 --> 00:12:22,902
interpender.
Alternatively, if you know that the

184
00:12:22,902 --> 00:12:27,432
interrupts going resolve itself very
quickly, you can just return, you can just

185
00:12:27,432 --> 00:12:32,194
leave interrupts masks the whole time the
interrupt handler is happening, and when

186
00:12:32,194 --> 00:12:37,097
it's done just the return from interrupt
construction usually turns off the

187
00:12:37,097 --> 00:12:39,930
interrupt.
Or, or, excuse me, turns back on the

188
00:12:39,930 --> 00:12:43,668
interrupts, if you will.
So it'll, it'll re-enable interrupts.

189
00:12:43,668 --> 00:12:48,550
So it's, you got to be a little careful
there, there's with interrupts inside of

190
00:12:48,550 --> 00:12:52,408
interrupts happening.
So, so that's, that's a great question, so

191
00:12:52,408 --> 00:12:56,180
what do you save in the exceptional PC.
On a interrupt.

192
00:12:56,180 --> 00:12:57,503
Oops.
So yeah.

193
00:12:57,503 --> 00:13:03,539
That's, that's, that's there.
So if you're, have instructions that are

194
00:13:03,539 --> 00:13:09,328
marching down the pipe in a two way in
order superscalar we'll say.

195
00:13:09,328 --> 00:13:15,530
You're, you're gonna save the PC of the
instruction that took the interrupt.

196
00:13:16,890 --> 00:13:19,897
Some architectures define this
differently.

197
00:13:19,897 --> 00:13:24,792
If you go look at something like x86
typically what gets saved in the

198
00:13:24,792 --> 00:13:28,289
exceptional pc is the next instruction to
execute.

199
00:13:28,289 --> 00:13:31,576
So it's, it's really dependent on
architectures.

200
00:13:31,576 --> 00:13:36,822
Some architectures will save the address
in the exceptional pc of the next

201
00:13:36,822 --> 00:13:42,696
instruction of program order to execute.
Some things will save the address of the

202
00:13:42,696 --> 00:13:49,410
instruction that actually took the trap
and as far as or took the exception or the

203
00:13:49,410 --> 00:13:53,293
interrupt.
So it's a little bit of a, a, a tradeoff

204
00:13:53,293 --> 00:13:56,620
there.
One of, one of the things that's actually

205
00:13:56,620 --> 00:14:00,160
hard is, you have a branch that takes an
exception.

206
00:14:00,160 --> 00:14:04,827
Do you store the target of the branch
location in the exceptional PC?

207
00:14:04,827 --> 00:14:08,479
Or do you, yeah.
You have to sort of resolve the branch

208
00:14:08,479 --> 00:14:11,726
first.
So that's one reason, actually, why lots

209
00:14:11,726 --> 00:14:17,678
of architectures favor just storing the PC
of the, instruction that took the trap and

210
00:14:17,678 --> 00:14:24,577
not the, sort of next" instruction."
So, I, I actually favor storing the PC of

211
00:14:24,577 --> 00:14:29,380
the instruction that took the, the trap,
and not the destination of that.

212
00:14:29,760 --> 00:14:40,951
Asynchronous interrupts similiar sort of
thing, Sometimes the handler wants to

213
00:14:40,951 --> 00:14:45,535
resume after sort of an instruction, where
someone might have to add PC plus four if

214
00:14:45,535 --> 00:14:49,955
you have a architecture exceptional PC
plus four if you need to jump over the

215
00:14:49,955 --> 00:14:55,309
instruction, for instance.
Something I didn't want so here this is

216
00:14:55,309 --> 00:14:59,841
the expression that I came up was, what
does this look like in a pipeline?

217
00:14:59,841 --> 00:15:03,069
And when do you note actually process the
interrupt.

218
00:15:03,069 --> 00:15:07,850
So here we have a five stage pipe.
So this is a little bit easier pipeline.

219
00:15:07,850 --> 00:15:14,586
And we can see, this, these bubbles here
are actually different types of interrupts

220
00:15:14,586 --> 00:15:19,632
or exceptions that can come out of the
pipe at different locations.

221
00:15:19,632 --> 00:15:24,745
So out in front here we can have maybe, a
PC address exception.

222
00:15:24,745 --> 00:15:29,823
What do I mean by that?
Well, some architectures won't allow you

223
00:15:29,823 --> 00:15:34,821
to execute, let's say, code out of,
certain regions of memory.

224
00:15:34,821 --> 00:15:40,061
So an example of this is actually in the
64 bit extension of x86.

225
00:15:40,061 --> 00:15:45,301
The 64 bit extension of x86 there's what
they call a memory hole.

226
00:15:45,301 --> 00:15:49,646
So between hope you'll call positive
memory and negative memory, so the top

227
00:15:49,646 --> 00:15:52,564
that, being such.
There's a big chunk of memory which no

228
00:15:52,564 --> 00:15:56,359
one's allowed to execute out of, or it's
not math, it's not real memory.

229
00:15:56,359 --> 00:16:00,533
So they have a 64 bit address space, but
they only use 42 bits of that 64 bit

230
00:16:00,533 --> 00:16:03,569
address space.
So if you've any bits in the middle which

231
00:16:03,569 --> 00:16:08,177
are not, set correctly, you're basically
going to be executing out of the memory

232
00:16:08,177 --> 00:16:12,406
hole, and that's an example of something
that can cause a PC address exception.

233
00:16:12,406 --> 00:16:15,388
So your PC sort of falls off the end of
math to memory.

234
00:16:15,388 --> 00:16:18,424
What do you do?
You're in some piece of memory, you're in

235
00:16:18,424 --> 00:16:21,460
some address which by definition is not a
valid address.

236
00:16:22,240 --> 00:16:24,313
Decode.
Illegal, illegal op code.

237
00:16:24,313 --> 00:16:27,122
So it doesn't, it isn't in your ISA
manual.

238
00:16:27,122 --> 00:16:32,807
Lots of, lots of op coding, coding space.
Usually most architectures purposely leave

239
00:16:32,807 --> 00:16:37,823
some space in there just for legal
instructions, or future expansion, if you

240
00:16:37,823 --> 00:16:43,374
will, and you want that to, to interrupt,
overflows and underflows out of your ALU.

241
00:16:43,374 --> 00:16:48,190
There's a whole host, if you have a
floating point unit here, of floating

242
00:16:48,190 --> 00:16:51,868
point exceptions.
Overflows, underflows, and denormalized

243
00:16:51,868 --> 00:16:55,251
sorts of instructions.
Data address exceptions.

244
00:16:55,251 --> 00:16:59,911
Well this would be if you're, let's say,
you have an unmapped memory address.

245
00:17:00,090 --> 00:17:04,571
Or you do a underlined mode or store.
So basically, every stage of your pipe

246
00:17:04,571 --> 00:17:07,498
here can be generating, some form of
interrupt.

247
00:17:07,498 --> 00:17:11,860
And then there's also asynchronous
interrupts, which we haven't drawn yet.

248
00:17:12,580 --> 00:17:18,518
Okay, so, good first question here is, how
do we handle multiple simultaneous

249
00:17:18,518 --> 00:17:24,140
interrupts in different pipeline stages,
happening all at the same time?

250
00:17:25,140 --> 00:17:30,644
Agree we should prioritize them.
So, what is the oldest instruction in the

251
00:17:30,644 --> 00:17:35,219
pipeline here?
So this is going to be the oldest

252
00:17:35,219 --> 00:17:39,862
instruction in the pipe.
So, let's, let's think about that.

253
00:17:39,862 --> 00:17:43,820
So that means it's probably going to want
to kill everything behind it.

254
00:17:44,360 --> 00:17:47,747
If, if there is an exception, that has
happened here.

255
00:17:47,946 --> 00:17:53,060
So if we were sort of, multiple things
generating exceptions here at one time.

256
00:17:53,340 --> 00:17:58,147
The oldest thing, the oldest instruction
in the pipe, the instruction that's been

257
00:17:58,147 --> 00:18:02,894
in the pipe the longest, is going to want
to kill all of the rest of the things.

258
00:18:03,075 --> 00:18:06,200
Going forward, though, so from a priority
perspective,

259
00:18:06,820 --> 00:18:09,900
Which of these things are probably the
highest priority?

260
00:18:17,380 --> 00:18:24,233
So, do you think we should be computing
overflow errors if the instruction op code

261
00:18:24,233 --> 00:18:30,220
is illegal?
Should be even decoding the instruction if

262
00:18:30,220 --> 00:18:35,300
the address that we try to fetch from our
instruction memory doesn't make any sense.

263
00:18:35,940 --> 00:18:43,005
So the priority of sort of the, when you
go to figure out where or which exception

264
00:18:43,005 --> 00:18:49,984
or which interrupt is the cause of the
exception should go this way, from left to

265
00:18:49,984 --> 00:18:56,478
right and then the you're going to, want
to actually kill going, going backwards.

266
00:18:56,478 --> 00:19:03,046
So let's, let's, let's skip that question
for a second and look at the, at this

267
00:19:03,046 --> 00:19:09,516
drawing.
So what you'll see here is we're actually

268
00:19:09,516 --> 00:19:19,555
going to just remember that we took some
exception for a particular instruction and

269
00:19:19,555 --> 00:19:23,129
just pipe it forward.
And then what we're going to do, is we're

270
00:19:23,129 --> 00:19:27,672
basically going to say, at the ends of the
pipe, once we know everything that's

271
00:19:27,672 --> 00:19:30,580
happened.
We're gonna call this the commit point.

272
00:19:32,220 --> 00:19:36,260
And that's going to feedback the other way
killing everything.

273
00:19:37,440 --> 00:19:42,460
Now,
Why do we put the commit point here?

274
00:19:47,320 --> 00:19:50,983
Could we put the commit point, let's say,
in this stage of the pipe?

275
00:19:50,983 --> 00:19:54,313
In the execute stage.
So, let's, let's define the commit point.

276
00:19:54,313 --> 00:19:58,587
The commit point is the point at which
architectural state of the machine is

277
00:19:58,587 --> 00:20:04,854
committed to the is committed, and, now
that may not be in the register file yet.

278
00:20:04,854 --> 00:20:08,317
Because by definition, in this point here,
it's not in the register file.

279
00:20:08,317 --> 00:20:10,609
It doesn't get there till the write back
stage.

280
00:20:10,609 --> 00:20:13,682
But nothing can change.
We're not, we can't read, we can't take a

281
00:20:13,682 --> 00:20:16,560
branch, we can't redirect, we can't take
any more exceptions.

282
00:20:17,820 --> 00:20:22,824
Well, by that definition we can't put the
commit point here, because further

283
00:20:23,025 --> 00:20:28,230
exceptions can happen after the commit
point, if we pull the commit point back.

284
00:20:28,424 --> 00:20:31,984
There are machines which do pull the
commit point back.

285
00:20:32,179 --> 00:20:37,358
You will see, when we start talking about
super, or out of order superscalars, we

286
00:20:37,358 --> 00:20:40,660
typically like to have the commit point at
the end.

287
00:20:40,660 --> 00:20:44,384
Cuz, or near the ends.
Because then you can sort of see if

288
00:20:44,384 --> 00:20:48,567
everything's resolved.
You can handle your interrupts, exceptions

289
00:20:48,567 --> 00:20:52,618
and have exceptions going out on the pipe
as long as possible.

290
00:20:52,618 --> 00:20:57,781
And if you try to pull your commit point
early, that forces you to actually resolve

291
00:20:57,781 --> 00:21:03,270
whatever exception is going to happen for
a particular instruction relatively early

292
00:21:03,270 --> 00:21:06,472
in the pipe.
So if we want to full this forward a

293
00:21:06,472 --> 00:21:11,700
stage, we would have to basically check
whether the address of a load or a store

294
00:21:11,700 --> 00:21:16,481
is valid in this pipe stage.
That may be possible because we finished

295
00:21:16,481 --> 00:21:19,720
the, calculation of the address right
here.

296
00:21:19,720 --> 00:21:23,333
But we haven't necessarily let's stay done
the TOB lookup.

297
00:21:23,333 --> 00:21:27,196
But we can pull the TOB lookup earlier or
something like that.

298
00:21:27,196 --> 00:21:31,060
That is possible.
And, and we'll see that some architectures

299
00:21:31,060 --> 00:21:35,234
try to pull that early.
Some architectures try to have, imprecise

300
00:21:35,234 --> 00:21:37,929
exceptions.
This is a, a scary, scary place.

301
00:21:37,929 --> 00:21:40,665
We're not going to be talking about this
very much.

302
00:21:40,665 --> 00:21:44,474
We're going to be talking about precise
exceptions mostly in this class.

303
00:21:44,474 --> 00:21:48,604
But an imprecise exception is one where
instructions are going down the pipe.

304
00:21:48,604 --> 00:21:52,896
You basically let the instruction sort of
pass the commit point and you tag the

305
00:21:52,896 --> 00:21:55,417
exception to the wrong instruction
effectively.

306
00:21:55,417 --> 00:21:57,885
It's not, not precise.
You can't stop on a dime.

307
00:21:57,885 --> 00:22:02,230
Architecture is, there are some embedded
processes that do things like that.

308
00:22:02,391 --> 00:22:06,844
And it's probably not the wisest thing to
do if you want to write a real operating

309
00:22:06,844 --> 00:22:08,762
system.
But like I said, yes.

310
00:22:08,762 --> 00:22:13,053
So the commit point being close to the end
is probably a good place.

311
00:22:13,053 --> 00:22:16,019
So at least after all your exceptions are
done.

312
00:22:16,019 --> 00:22:19,238
So by the time we get to this red dashed
line here,

313
00:22:19,238 --> 00:22:24,034
So we're after the computation of the
exceptional PC and everything, we know

314
00:22:24,034 --> 00:22:28,636
that we're going to be committing.
Or we, or at least we have a thumbs up or

315
00:22:28,636 --> 00:22:33,141
a thumbs down.
And if it's a thumbs down we kill

316
00:22:33,141 --> 00:22:40,860
everything behind here.
One thing I did want to say is, cause.

317
00:22:42,220 --> 00:22:46,661
What does that register do?
Well that register tells us, why did we

318
00:22:46,661 --> 00:22:50,959
take the exception.
So it's a priority encoder, which

319
00:22:50,959 --> 00:22:54,860
priority, prioritizes, as we said, this
direction.

320
00:22:55,120 --> 00:22:58,860
And we'll determine the cause of the, of
the exception.

321
00:23:01,720 --> 00:23:05,200
Asynchronous interrupts.
Hm.

322
00:23:06,200 --> 00:23:09,872
There's different places to wire this in.
You just sort of have to tag it to

323
00:23:09,872 --> 00:23:12,869
something, but you have to make sure that
you actually take it.

324
00:23:12,869 --> 00:23:16,831
So the simplest thing to do is just to put
it into this big log at the end of the

325
00:23:16,831 --> 00:23:20,263
pipe here at the commit point.
And have the asynchronous interrupt show

326
00:23:20,263 --> 00:23:22,582
up at the end of the pipe.
Not all pipes do this.

327
00:23:22,582 --> 00:23:26,207
Some pipes will actually inject
asynchronous interrupt at the beginning of

328
00:23:26,207 --> 00:23:30,266
the pipe, allow it to go down the end, and
arbitrate like everything else here at the

329
00:23:30,266 --> 00:23:33,146
end stage of the pipe.
The simplest thing to do is to have it

330
00:23:33,146 --> 00:23:36,823
come in here, and that's because otherwise
you might drop this asynchronous interrupt

331
00:23:36,823 --> 00:23:39,504
on the ground, or not actually take the
asynchronous interrupt.

332
00:23:39,504 --> 00:23:42,100
You want to make sure you actually have a
chance to take it.

333
00:23:43,679 --> 00:23:49,707
Exceptional PC.
Takes the PC and, and pipes it forward and

334
00:23:49,707 --> 00:23:54,685
saves that in a register.
But this only gets loaded on a exception

335
00:23:54,685 --> 00:24:03,584
or interrupt happening.
Okay, so that's, that's commit points.

336
00:24:03,928 --> 00:24:10,538
That's, that's important for out of order
superscalars.

337
00:24:10,538 --> 00:24:14,312
Because we're going to have to start
thinking about, where is the commit point

338
00:24:14,312 --> 00:24:16,827
of a processor?
And it may not be where we want it.

339
00:24:16,827 --> 00:24:20,953
Or it's possible that we will not be able
to put the commit point anywhere in the

340
00:24:20,953 --> 00:24:23,318
processor, and actually have the processor
work.

341
00:24:23,318 --> 00:24:27,192
So today, we're going to actually look at
a processor where it's not possible to

342
00:24:27,192 --> 00:24:30,362
have precise exceptions.
So there is no line we can cut and say,

343
00:24:30,362 --> 00:24:39,196
this is the commit point.
Let see, so we, we covered all this.

344
00:24:40,920 --> 00:24:47,292
Speculation.
This is going back to like, our example of

345
00:24:47,292 --> 00:24:50,910
PC plus four.
Do we want to assume the exception's going

346
00:24:50,522 --> 00:24:53,881
to happen?
Or the interrupt is going to happen, or

347
00:24:53,881 --> 00:24:59,549
not?
So we're calling it an exception for a

348
00:24:59,549 --> 00:25:01,562
reason.
It is the exceptional case.

349
00:25:01,562 --> 00:25:05,412
It is not the common case.
So we want to somehow predict what our

350
00:25:05,412 --> 00:25:09,498
branch vector tells us or PC4 plus four or
fall through or PC, you know, the next

351
00:25:09,498 --> 00:25:12,696
instruction.
We do not want to just have we don't have

352
00:25:12,696 --> 00:25:17,315
to wait till the end of the pipe to know
whether an exception is taken or not

353
00:25:17,315 --> 00:25:19,980
before we try to go get the next
instruction.

354
00:25:21,900 --> 00:25:29,461
One other thing When we start to go to out
of order pipelines, we're going to start

355
00:25:29,461 --> 00:25:35,040
to need some, recovery mechanism here.
We're going to be processing instructions

356
00:25:35,040 --> 00:25:38,740
out of order.
So if they, we might be taking the

357
00:25:38,740 --> 00:25:45,118
interrupt for, in instruction after it,
it's let's say, subsequent instructions

358
00:25:45,118 --> 00:25:49,920
have either committed or sort of started
to go down the pipe.

359
00:25:49,920 --> 00:25:54,093
And you sort of get some out of order time
questions.

360
00:25:54,093 --> 00:25:59,919
So we're going to look at a few different
solutions for this, for recovery.

361
00:25:59,919 --> 00:26:04,880
In our, in our simple cases, we just
basically flush the pipe,

362
00:26:06,880 --> 00:26:10,084
And kill everything behind us.
In more complicated things.

363
00:26:10,084 --> 00:26:14,470
We're actually going to have extra
register files that are basically going to

364
00:26:14,470 --> 00:26:18,125
be shadow register files.
We're going to keep track of everything

365
00:26:18,125 --> 00:26:21,611
that's going on in the processor, of what
should have happened.

366
00:26:21,611 --> 00:26:25,097
And then we're gonna dump that into our
true architectural.

367
00:26:25,266 --> 00:26:28,189
Excuse me.
Into our physical register file, and we'll

368
00:26:28,189 --> 00:26:34,857
look at that, maybe today, or next class.
We should bypass.

369
00:26:34,857 --> 00:26:37,955
Bypassing is good.
You should not have to wait to the end of

370
00:26:37,955 --> 00:26:48,730
the pipe.
Okay so let's look at a time diagram here,

371
00:26:48,730 --> 00:26:56,647
of an add that takes an overflow.
Instruction one here is an add and we

372
00:26:56,647 --> 00:27:00,896
speculate that it does not take a, any
sort of exception.

373
00:27:00,896 --> 00:27:05,980
So we fetch the next instruction.
We start sticking ads on the pipe.

374
00:27:06,940 --> 00:27:12,154
In the except in the execute stage of the
pipe, we determine that there isn't

375
00:27:12,154 --> 00:27:15,569
overflow.
Well as we said, as we said, we don't

376
00:27:15,569 --> 00:27:20,254
actually try to do something about this
until the commit stage at the pipe.

377
00:27:20,254 --> 00:27:25,440
So in, in our simple pipe our commit stage
is at the end of this memory stage.

378
00:27:25,440 --> 00:27:30,626
So we actually pipe it forward one stage.
At that point, we restart the front of the

379
00:27:30,626 --> 00:27:33,375
pipe, and we start fetching, the, handler
code.

380
00:27:33,375 --> 00:27:37,748
The exceptional handler code.
And we're going to basically kill behind

381
00:27:37,748 --> 00:27:40,560
us, turn everything behind us into a
no-op.

382
00:27:40,900 --> 00:27:50,146
So.
We'll saying we're bypassing out of ex1

383
00:27:50,146 --> 00:27:57,030
here, into the Well, okay, let's say we go
to this one instead.

384
00:27:57,030 --> 00:28:01,235
Or we, we can come out here, you'll see
we're bypassing out of the memory stage,

385
00:28:01,235 --> 00:28:05,603
or the, the memory stage, back to the
register fetch stage of instruction three.

386
00:28:05,603 --> 00:28:09,377
I think that's what you just asked about.
What's going to happen is, we're going to

387
00:28:09,701 --> 00:28:14,015
let that bypass happen, we're going to let
that data come around, through the bypass

388
00:28:14,015 --> 00:28:16,387
network.
But what's going to happen is, we're, at

389
00:28:16,387 --> 00:28:20,270
that same time, we're sending the kill,
kill signal behind us in the pipe.

390
00:28:20,270 --> 00:28:23,986
Or instruction one is going to be killing
everything behind it in, in the pipe.

391
00:28:23,986 --> 00:28:27,225
So we're going to bypass the data around.
It's going to get bypassed.

392
00:28:27,225 --> 00:28:30,322
It's going to end up, in, in the pipeline
register in the cycle.

393
00:28:30,322 --> 00:28:33,323
But it's going to be killed basically at
the end of that cycle.

394
00:28:33,323 --> 00:28:35,420
A better example is actually here.
Let's say,

395
00:28:35,420 --> 00:28:42,147
It bypasses to instruction two from the
execute stage to the decode stage of the

396
00:28:42,147 --> 00:28:45,146
pipe.
That's actually gonna going to loaded into

397
00:28:45,146 --> 00:28:48,494
the pipeline register of the fetched,
operand.

398
00:28:48,494 --> 00:28:54,283
And then it's going to go forward into the
execute stage, ex2 here, for instruction

399
00:28:54,283 --> 00:28:55,817
two.
So we bypassed it.

400
00:28:55,817 --> 00:29:00,281
We started executing that instruction.
Everything was going fine.

401
00:29:00,281 --> 00:29:03,490
But then, we just come along, and we kill
it.

402
00:29:03,490 --> 00:29:05,841
So, we're speculatively executing, it's
called.

403
00:29:05,841 --> 00:29:08,297
So we're, it's a speculative execution
pipeline.

404
00:29:08,297 --> 00:29:11,589
We are assuming, we're predicting that
everything is going fine.

405
00:29:11,589 --> 00:29:15,300
And then we're going to be killing behind
us when something goes wrong.
