WEBVTT

00:00:00.599 --> 00:00:05.060
Now let's figure out how exceptions impact
pipelined execution.

00:00:05.060 --> 00:00:09.900
When an exception occurs because of an illegal
instruction or an external interrupt, we need

00:00:09.900 --> 00:00:14.820
to store the current PC+4 value in the XP
register and load the program counter with

00:00:14.820 --> 00:00:18.730
the address of the appropriate exception handler.

00:00:18.730 --> 00:00:23.260
Exceptions cause control flow hazards since
they are effectively implicit branches.

00:00:23.260 --> 00:00:29.460
In an unpipelined implementation, exceptions
affect the execution of the current instruction.

00:00:29.460 --> 00:00:34.160
We want to achieve exactly the same effect
in our pipelined implementation.

00:00:34.160 --> 00:00:39.100
So first we have to identify which one of
the instructions in our pipeline is affected,

00:00:39.100 --> 00:00:44.670
then ensure that instructions that came earlier
in the code complete correctly and that we

00:00:44.670 --> 00:00:49.789
annul the affected instruction and any following
instructions that are in the pipeline.

00:00:49.789 --> 00:00:53.179
Since there are multiple instructions in the
pipeline, we have a bit of sorting out to

00:00:53.179 --> 00:00:54.179
do.

00:00:54.179 --> 00:00:59.940
When, during pipelined execution, do we determine
that an instruction will cause an exception?

00:00:59.940 --> 00:01:05.860
An obvious example is detecting an illegal
opcode when we decode the instruction in the

00:01:05.860 --> 00:01:07.600
RF stage.

00:01:07.600 --> 00:01:11.280
But we can also generate exceptions in other
pipeline stages.

00:01:11.280 --> 00:01:16.140
For example, the ALU stage can generate an
exception if the second operand of a DIV instruction

00:01:16.140 --> 00:01:17.780
is 0.

00:01:17.780 --> 00:01:23.100
Or the MEM stage may detect that the instruction
is attempting to access memory with an illegal

00:01:23.100 --> 00:01:24.299
address.

00:01:24.299 --> 00:01:29.020
Similarly the IF stage can generate a memory
exception when fetching the next instruction.

00:01:29.020 --> 00:01:33.369
In each case, instructions that follow the
one that caused the exception may already

00:01:33.369 --> 00:01:37.079
be in the pipeline and will need to be annulled.

00:01:37.079 --> 00:01:42.780
The good news is that since register values
are only updated in the WB stage, annulling

00:01:42.780 --> 00:01:45.320
an instruction only requires replacing it
with a NOP.

00:01:45.320 --> 00:01:51.630
We won't have to restore any changed values
in the register file or main memory.

00:01:51.630 --> 00:01:52.929
Here's our plan.

00:01:52.929 --> 00:01:58.250
If an instruction causes an exception in stage
i, replace that instruction with this BNE

00:01:58.250 --> 00:02:05.749
instruction, whose only side effect is writing
the PC+4 value into the XP register.

00:02:05.749 --> 00:02:10.080
Then flush the pipeline by annulling instructions
in earlier pipeline stages.

00:02:10.080 --> 00:02:16.500
And, finally, load the program counter with
the address of the exception handler.

00:02:16.500 --> 00:02:21.720
In this example, assume that LD will generate
a memory exception in the MEM stage, which

00:02:21.720 --> 00:02:24.090
occurs in cycle 4.

00:02:24.090 --> 00:02:29.050
The arrows show how the instructions in the
pipeline are rewritten for cycle 5, at which

00:02:29.050 --> 00:02:35.810
point the IF stage is working on fetching
the first instruction in the exception handler.

00:02:35.810 --> 00:02:39.050
Here are the changes required to the execution
pipeline.

00:02:39.050 --> 00:02:44.220
We modify the muxes in the instruction path
so that they can replace an actual instruction

00:02:44.220 --> 00:02:50.090
with either NOP if the instruction is to be
annulled, or BNE if the instruction caused

00:02:50.090 --> 00:02:51.700
the exception.

00:02:51.700 --> 00:02:56.800
Since the pipeline is executing multiple instructions
at the same time, we have to worry about what

00:02:56.800 --> 00:03:01.530
happens if multiple exceptions are detected
during execution.

00:03:01.530 --> 00:03:07.170
In this example assume that LD will cause
a memory exception in the MEM stage and note

00:03:07.170 --> 00:03:12.550
that it is followed by an instruction with
an illegal opcode.

00:03:12.550 --> 00:03:18.900
Looking at the pipeline diagram, the invalid
opcode is detected in the RF stage during

00:03:18.900 --> 00:03:25.520
cycle 3, causing the illegal instruction exception
process to begin in cycle 4.

00:03:25.520 --> 00:03:31.570
But during that cycle, the MEM stage detects
the illegal memory access from the LD instruction

00:03:31.570 --> 00:03:37.540
and so causes the memory exception process
to begin in cycle 5.

00:03:37.540 --> 00:03:42.870
Note that the exception caused by the earlier
instruction (LD) overrides the exception caused

00:03:42.870 --> 00:03:48.840
by the later illegal opcode even though the
illegal opcode exception was detected first.

00:03:48.840 --> 00:03:54.290
.348 That's the correct behavior since once
the execution of LD is abandoned, the pipeline

00:03:54.290 --> 00:04:00.660
should behave as if none of the instructions
that come after the LD were executed.

00:04:00.660 --> 00:04:05.210
If multiple exceptions are detected in the
*same* cycle, the exception from the instruction

00:04:05.210 --> 00:04:10.570
furthest down the pipeline should be given
precedence.

00:04:10.570 --> 00:04:15.150
External interrupts also behave as implicit
branches, but it turns out they are a bit

00:04:15.150 --> 00:04:18.160
easier to handle in our pipeline.

00:04:18.160 --> 00:04:23.790
We'll treat external interrupts as if they
were an exception that affected the IF stage.

00:04:23.790 --> 00:04:27.430
Let's assume the external interrupt occurs
in cycle 2.

00:04:27.430 --> 00:04:32.560
This means that the SUB instruction will be
replaced by our magic BNE to capture the PC+4

00:04:32.560 --> 00:04:38.370
value and we'll force the next PC to be the
address of the interrupt handler.

00:04:38.370 --> 00:04:42.540
After the interrupt handler completes, we'll
want to resume execution of the interrupted

00:04:42.540 --> 00:04:47.602
program at the SUB instruction, so we'll code
the handler to correct the value saved in

00:04:47.602 --> 00:04:52.930
the XP register so that it points to the SUB
instruction.

00:04:52.930 --> 00:04:55.780
This is all shown in the pipeline diagram.

00:04:55.780 --> 00:05:00.980
Note that the ADD, LD, and other instructions
that came before SUB in the program are unaffected

00:05:00.980 --> 00:05:03.639
by the interrupt.

00:05:03.639 --> 00:05:08.440
We can use the existing instruction-path muxes
to deal with interrupts, since we're treating

00:05:08.440 --> 00:05:11.210
them as IF-stage exceptions.

00:05:11.210 --> 00:05:17.789
We simply have to adjust the logic for IRSrc_IF
to also make it 1 when an interrupt is requested.