W4 RISC V ISA II EN — Transcript
Full transcript
- 0:11So, starting from this class, also
- 0:15in in this class also we'll continue to
- 0:17respect instruction set architecture and
- 0:19machine language.
- 0:20And after this
- 0:22class inshallah, we are going to start
- 0:24to see the actual hardware
- 0:26implementation of a RISC-V processor.
- 0:30So, in the last class we we said that
- 0:32binary representation of instructions
- 0:36is only in terms of ones and zeros. So,
- 0:39because computers only understand ones
- 0:41and zeros. And in RISC-V
- 0:44all instructions are 32-bit except for
- 0:48the compressed case. If your processor
- 0:50supports the compressed case, then
- 0:52instructions can be also 16-bit.
- 0:55The good point in here
- 0:58that RISC-V follow all of these
- 1:00principles, simplicity favors
- 1:02regularity.
- 1:04The
- 1:05For example, in Intel
- 1:07instructions are between 1 byte and 16
- 1:10byte. Maybe it changed because they are
- 1:12changing their ISA instruction set
- 1:14architecture a lot.
- 1:15But in Intel, for example, all
- 1:17instructions can be between 1 and 16
- 1:21byte in x86.
- 1:24But in RISC-V
- 1:26it is simple. All instructions are
- 1:2832-bit.
- 1:30And if there is a C extension, it is not
- 1:33mandatory
- 1:34then 16-bit instructions are also
- 1:36supported.
- 1:38And we saw the four types of instruction
- 1:40formats, R, I, S, U type.
- 1:43And in here, this figure shows the
- 1:46immediate encoding depending on the
- 1:49instruction type.
- 1:52And in here you can see that the
- 1:55immediate
- 1:56uh total immediate 31-bit
- 1:59and its organization immediate
- 2:02organization. For example, for B-type
- 2:04instructions, immediate zero is always
- 2:06zero because it is a jump instruction.
- 2:08And since we are jumping in terms of
- 2:1016-bits, its least significant bit is
- 2:13always zero.
- 2:17And other
- 2:19parts of the immediate, for example,
- 2:21designed in this way.
- 2:25And this immediate is important because
- 2:27we have some instructions that also has
- 2:30immediate field.
- 2:31Uh
- 2:32so, in here, there is a
- 2:35important point. For example, we have a
- 2:38add immediate instruction,
- 2:40but we don't have subtract immediate.
- 2:42Why?
- 2:45Because it is unnecessary.
- 2:47The difference between add immediate and
- 2:50sub immediate,
- 2:53for example, add immediate and sub
- 2:54immediate. So, instead of
- 2:59For example, you want to subtract minus
- 3:01X.
- 3:04For sorry, you want to subtract X, for
- 3:06example. So, instead of defining a sub
- 3:10sub immediate instruction, in add
- 3:12immediate, you can use minus X. So,
- 3:14adding with minus X is equal to
- 3:16subtracting
- 3:18it X.
- 3:19So, since compiler can do it very
- 3:22easily, RISC-V is not putting any
- 3:24instruction for it.
- 3:25Because compiler can do it. So, there is
- 3:27no need to put another instruction. In
- 3:30this way, our hardware becomes simpler.
- 3:32So, this is the very good point for
- 3:34RISC-V. If the instruction can be
- 3:39generated by the compiler, then RISC-V
- 3:41is not putting it in instruction set
- 3:43architecture.
- 3:45This is also another figure that shows
- 3:47the immediate encoding in RISC-V.
- 3:50So, immediate bits
- 3:52mostly occupy constant instruction bits.
- 3:55As you can see in here, for example, the
- 3:57place of RS1, depending on the
- 4:00uh
- 4:02this instruction types, the place of RS1
- 4:05is same, RS place of RS2 is same,
- 4:08function three is always same.
- 4:11For this reason, immediate is a little
- 4:13bit distributed. In the last class, we
- 4:16we mentioned about it, but we didn't
- 4:18mention why it is distributed. You can
- 4:21see the reasoning in here.
- 4:24And sign bit is always at 31 location.
- 4:27Location of 31 shows the sign bit.
- 4:30It's a most significant bit of
- 4:32instruction.
- 4:34So, this way, this immediate encoding
- 4:36simplifies the hardware to build the
- 4:38micro micro processor.
- 4:48So, this is figure also shows the
- 4:5132-bit immediate fields
- 4:53and type of instruction formats.
- 4:56Uh you can check it then.
- 4:59But, of course, you don't need to
- 5:00memorize them. No need for to memorize
- 5:03them.
- 5:06There is one exception in here.
- 5:09Previously, I mentioned that there are
- 5:11some instruction format RISC-V
- 5:14UJ.
- 5:15And
- 5:18in floating point, there are different
- 5:21There is a different format. It's named
- 5:23as R4 type. And this is important for
- 5:26you if you are implementing the floating
- 5:28point extension.
- 5:31So,
- 5:32in this R4 type, there are four RS uh
- 5:36There are three RS fields. And total,
- 5:40there are four registers.
- 5:43The difference is that in here, there is
- 5:45RS1, RS2, but there is also RS3. Because
- 5:48it is multiply and add instruction. What
- 5:49is a multiply and add instruction?
- 5:52RD is equal to RS1 * RS2 + RS3.
- 5:57So, this is
- 5:59a
- 5:59instruction specific to floating point
- 6:02floating point extension FD and Q
- 6:05extensions.
- 6:07And in this format,
- 6:08this is R4 type. R4 means that there are
- 6:11four registers in this format.
- 6:14But, this is not important for you. If
- 6:16you are not implementing floating point
- 6:17operations, then this is not a
- 6:19uh interest for you.
- 6:27This slide shows the compressed
- 6:29instruction formats. In the last class,
- 6:32I briefly mentioned that in compressed
- 6:34instruction formats, you can access only
- 6:36a limited set of registers.
- 6:39For example, in here, it says that if
- 6:41the instruction is compressed, then you
- 6:44can specify specify registers between X8
- 6:47and X15 only.
- 6:49We are using 3-bit register.
- 6:51And in this 3-bit, by using this 3-bit,
- 6:53you are
- 6:54encoding these eight registers between
- 6:56X8 and X15. And compressed instructions
- 7:01has different formats.
- 7:03They have different formats.
- 7:06Uh in here, immediates are changing
- 7:09between six and 11 bits. Opcode is two
- 7:11bits only. This opcode is only two bit.
- 7:16And these are the types.
- 7:18But, of course, you don't need to
- 7:19memorize them. Even we are developing
- 7:21lots of RISC-V processor, we are not
- 7:23memorizing them. We are just checking
- 7:25while developing.
- 7:26Uh we are checking them, applying them,
- 7:28then that's all.
- 7:30But, the good to good point in here is
- 7:32that RISC-V if there is an RS1 in an
- 7:36instruction, then it place is always
- 7:38same. This is a good thing for RISC-V.
- 7:41For example, in ARM, uh it is arm is not
- 7:44following this convention.
- 7:46The
- 7:46location of RS1 is changing in arm
- 7:49architecture.
- 7:51Since in RISC-V it is in the same
- 7:53location, when you implement a decoder
- 7:56in SystemVerilog, then your decoder
- 7:59works faster than arm's decoders. This
- 8:01is a good point for RISC-V.
- 8:05In here, there is a
- 8:07example about interpreting information
- 8:10language.
- 8:11You see, we have a instruction in here.
- 8:14It's 0x41.
- 8:17This instruction
- 8:19is hexadecimal format, and this is the
- 8:20binary format.
- 8:22For example, you want to disassemble
- 8:24this this
- 8:26binary code.
- 8:28Disassemble means that for example,
- 8:30assembly means that you are converting
- 8:33the instruction to assembly assembly
- 8:35version. Disassembly means that you are
- 8:37converting the binary to
- 8:40assembly version. Disassembly.
- 8:42So, assembly means that like converting
- 8:44the
- 8:46assembly instruction
- 8:48to binary version. Disassembly is the
- 8:50reverse of it.
- 8:51So, for example, if I want to do
- 8:54disassembly, get the disassembly version
- 8:56of this
- 8:57instruction,
- 8:59then in here, the first step is that to
- 9:01look at the op field and understand the
- 9:04operation type.
- 9:05For example, in here, it's op is 51.
- 9:09And function if op is 51, then it is
- 9:12related to an addition, subtraction, and
- 9:15or any operations between them.
- 9:18And then function is function three is
- 9:20the
- 9:21is the field that specifies the type
- 9:23type of the operation.
- 9:25So, in here, I'm taking function three,
- 9:26and it is zero. Then it is either
- 9:31add or sub instruction. So, in this
- 9:33case, I'm taking the function seven
- 9:35field,
- 9:36and then understand that this is a sub
- 9:38instruction.
- 9:39So, you need to first start with op
- 9:41and then depending on op
- 9:44you need to look at function three and
- 9:46function seven, but of course in in some
- 9:48instructions there is no function three,
- 9:50for example.
- 9:52Function seven itself is on is enough in
- 9:55this case.
- 9:57So, and this is also another instruction
- 9:59that corresponds to add immediate I type
- 10:01instruction. For example, in here there
- 10:03is no function seven, right? We are we
- 10:06can see that op is 19.
- 10:09So, 19 is add immediate immediately if
- 10:12its function three is 000 and we are not
- 10:14looking to function seven, for example,
- 10:16in here.
- 10:18Most likely you will not do this
- 10:20uh disassembly yourself. We are always
- 10:23using the
- 10:25tools to do disassembling,
- 10:28but this is the methodology to do it.
- 10:38And this is the machine code.
- 10:40It's It's field specific fields of these
- 10:42two two
- 10:44instructions.
- 10:48So, this is a summary for the
- 10:49instruction formats formats.
- 10:54Uh
- 10:55and in here SP and UG are near the same,
- 11:00but their immediate encoding is changing
- 11:02a little bit.
- 11:04For example, for S type
- 11:06immediate zero is important because in S
- 11:08type we are doing
- 11:10store, for example, uh memory operations
- 11:13actually by using S type.
- 11:15Uh but, for example, in B type we are
- 11:18jumping. This is jump and branch
- 11:20instructions, for example, in G type or
- 11:22B type. Then in this case immediate zero
- 11:24is always zero, for example, immediate
- 11:26starts from one in these instructions.
- 11:29Because it's always
- 11:30uh immediate zero, first bit of the
- 11:32immediate is zero in this in this
- 11:35instructions.
- 11:36implicitly
- 11:40Is there any questions until this point?
- 11:47Then we can switch to RISC-V programming
- 11:50section and we can inspect some RISC-V
- 11:53programming examples
- 11:56and then start the architecture. Because
- 11:58in order to build an architecture, you
- 12:00need to know how to program this
- 12:02architecture.
- 12:03Uh until now in the first four weeks
- 12:07uh we
- 12:09solved uh
- 12:11some System Verilog and then
- 12:14uh instruction set architecture specific
- 12:15topics. And starting from the next
- 12:17lecture, inshallah, we are going to see
- 12:19the
- 12:20hardware microarchitecture
- 12:22implementation. So in in we were
- 12:25starting with big A architecture
- 12:27architecture.
- 12:28Then we will switch to go down to one
- 12:30level below
- 12:32and look at the microarchitecture
- 12:34implementation.
- 12:37So this The first topic is the
- 12:39conditional statements, if statement,
- 12:41if-else statement, loops and loops,
- 12:43while and for loops.
- 12:48You see there is a C code in here.
- 12:51C code checks whether I is equal to G
- 12:54and if it is equal, then
- 12:56it does this computation.
- 12:58Otherwise
- 13:00it continues and does this computation.
- 13:03But in any case, this computation is
- 13:05done, but this condition this
- 13:07operation is conditional
- 13:10and depends on this condition.
- 13:13So how can we write a RISC-V assembly
- 13:15code for this specific C code?
- 13:19Normally, we are not writing
- 13:21writing RISC-V assembly codes. We are
- 13:24generally writing C code.
- 13:26But in here, since we are trying to be
- 13:28familiar with the instruction set
- 13:30architecture, we need to see how C code
- 13:33is converted to RISC-V assembly.
- 13:38In here,
- 13:39we can use branch equal or branch not
- 13:41equal instruction.
- 13:43In this example, when compiler converts,
- 13:48compiler used branch not equal
- 13:49instruction. And these are the initial
- 13:52location of these values. For example,
- 13:55S0 register keeps the value of F F, S1
- 13:59keeps the value of G G.
- 14:02And in the first
- 14:04instruction, it compares S3 with S4. S3
- 14:10is I and S4 is J. So, it does this
- 14:13comparison. But, it is doing the reverse
- 14:15of it, not equal.
- 14:17It is saying that if they are not equal,
- 14:20then jump to L1.
- 14:22L1 label.
- 14:24So, it is saying that if they are not
- 14:26equal, this I is not equal to G, then
- 14:30jump to here directly. It's the reverse
- 14:32of it.
- 14:35If they are equal,
- 14:37then it continues,
- 14:39and at then it also does this operation,
- 14:42sub operation.
- 14:43So, it it compares these two registers,
- 14:46and then
- 14:48does this operation. This is This
- 14:50corresponds to this F equal to G plus H
- 14:53operation corresponds to this add.
- 14:56And then it adds S0 and S1,
- 14:58which is G and H.
- 15:00And then it continues and does the sub
- 15:02operation. But, if they are not equal,
- 15:04then it jumps to L1. It doesn't run this
- 15:07It doesn't run this uh
- 15:09instruction, then jumps to L1 point
- 15:12immediately.
- 15:17In here, there is a if else one. If else
- 15:20is different, because in the previous
- 15:22version, we were running
- 15:24We are running this
- 15:27this instruction in any case, but in
- 15:29here
- 15:30we should either run this one or this
- 15:33one.
- 15:34And in if else version of it
- 15:38still we are looking to branch not
- 15:39equal.
- 15:41And if they are not equal, we are going
- 15:44we are switching to this else statement
- 15:47and running this else statement.
- 15:49But since
- 15:51either I should run this one or this one
- 15:55then
- 15:56after if they are not equal
- 15:59uh
- 16:00if they are equal, then
- 16:02we run this add instruction. We execute
- 16:05this
- 16:06add instruction.
- 16:07But after doing this instruction, I need
- 16:10to jump to this point because I
- 16:11shouldn't run
- 16:13this this instruction. For this reason,
- 16:15we are putting compiler puts a G done to
- 16:18here. G done means get jump jump done.
- 16:22So, it directly jumps after if they are
- 16:25equal
- 16:26then it runs this add instruction, then
- 16:29comes to here, then
- 16:31jumps to this done location without
- 16:33running this instruction.
- 16:35Is it clear, right?
- 16:43In here, there is also another example.
- 16:45It is for while loops.
- 16:48Our C code
- 16:53tries to compute two two to the X, two
- 16:55to the power of X.
- 16:57Uh actually, it determines the power of
- 17:00X such that two to the X is 128.
- 17:04So, it tries to find this X. What is
- 17:07this X value of X?
- 17:09So,
- 17:10in here, I have two variables in C code.
- 17:13One of them is pow. It starts with one
- 17:15and X
- 17:16is zero.
- 17:18And I'm always doing this computation
- 17:21both both times two and increasing to X
- 17:25each time by one.
- 17:27And trying to find
- 17:29trying to loop in here until both
- 17:32becomes 128, and then it exits this
- 17:35loop.
- 17:36So, in this case, I I can find that this
- 17:38X value.
- 17:40And what is the RISC-V assembly code in
- 17:42here?
- 17:43I am doing some initialization.
- 17:47S0 becomes one.
- 17:500 + 1 S0 S0
- 17:52becomes one.
- 17:54Uh it is X.
- 17:56Uh sorry, it is it is it is one. It is
- 17:58it is pow pow.
- 18:00Uh
- 18:01S1 is zero.
- 18:02Then it is it is X.
- 18:05And then
- 18:06for this constant, I am loading it to
- 18:08the T0 register.
- 18:10Uh in order to to load it, I'm just
- 18:13doing a basic addition. Add immediate. 0
- 18:15+ 128. Zero register is always zero. 0 +
- 18:18128. T0 keeps the 128.
- 18:22And then while loop starts here. This is
- 18:25a label for the while loop.
- 18:28I am doing a comparison in here. If S0
- 18:30is equal to T0,
- 18:32if it is
- 18:34equal, it means that S0 is equal to 128.
- 18:37If it is
- 18:39equal, we are
- 18:40going to we are jumping to this done
- 18:42location. Otherwise,
- 18:44we are doing multiplication operation in
- 18:46here. But for multiplication, we are not
- 18:49using multiplication instruction.
- 18:51Instead, we are doing one-bit shift.
- 18:54One-bit
- 18:55left shift means that multiply by two in
- 18:58binary. So, we are doing one-bit left
- 19:01shift
- 19:02immediate uh immediate shift. Immediate
- 19:05is one in here. And then doing addition
- 19:07instruction to increase this X counter.
- 19:11And after this operation, jumping to the
- 19:14beginning of the while. So,
- 19:16after some iterations,
- 19:20when
- 19:21power becomes 128 as a result of this
- 19:24comparison,
- 19:26we are jumping to done. And at that
- 19:27point, this S1
- 19:30register keeps the value of X that shows
- 19:32to this X.
- 19:36The value of X that
- 19:38it's
- 19:392 to the power of like X becomes 128.
- 19:46This was while loops. And in for loop,
- 19:50uh there are four parts in for loop.
- 19:53Uh one of them is initialization. One of
- 19:56them is condition, loop operation, and
- 19:58statement.
- 19:59So, you know for loop, right? In you you
- 20:02are familiar with the C programming or
- 20:03MATLAB or in any programming language,
- 20:06you know the for loops.
- 20:08So, in here, I have a C code. And this C
- 20:11code at the numbers from 0 to 9.
- 20:14And it computes
- 20:16the result in sum.
- 20:18And I is my
- 20:19counter in here, for loop counter.
- 20:22When you look at its respect assembly
- 20:24code,
- 20:26uh S1 corresponds to the sum. It starts
- 20:29with 0. And S0 starts with
- 20:33S0 is I.
- 20:35And this I starts with
- 20:370. It's initialized at 0 in for loops.
- 20:42And I have also a constant in here, 10.
- 20:45We
- 20:46We This is my limit.
- 20:48And at each time,
- 20:50uh
- 20:50I am comparing whether S0, which is my
- 20:54I counter, is equal to one or 10 or not.
- 20:58And if it is 10,
- 21:00then
- 21:01jumping to done location. Otherwise,
- 21:04I'm doing this computation. This
- 21:06computation and this computation is done
- 21:09in this in here.
- 21:11So, we are increasing the
- 21:14sum in here. Sum is
- 21:16increased by S0 each time and then S0 is
- 21:20increased by one also.
- 21:23And whenever this I becomes 10,
- 21:27it jumps to done and sum is
- 21:31resulted as a
- 21:33addition of the numbers from zero to
- 21:34nine.
- 21:43In here, there is also another
- 21:45C code example. It adds the power of two
- 21:47from one to 100.
- 21:55So, this is the corresponding code then.
- 21:59Sum starts with zero. I starts with from
- 22:02one. You can see the initialization in
- 22:04here.
- 22:05Here is initialization. And then in
- 22:08here, there's condition check.
- 22:11And this
- 22:14multiply by two operation done by shift
- 22:17left.
- 22:18And this is the summation operation done
- 22:21in here.
- 22:25Generally, by the way, we are not
- 22:27writing assembly code, but for example,
- 22:30if you design for example, you design
- 22:32the RISC-V processor and you want to
- 22:34test some specific cases, in this case,
- 22:36we are writing assembly code. But
- 22:37generally, nobody writes assembly code.
- 22:43We are all writing the C code or higher
- 22:46level C++, C# codes and then compiling
- 22:49them for RISC-V processor.
- 22:55And by the way, most people are not even
- 22:56writing code. They are just using the
- 22:58AI.
- 23:03This is an alternative version of this
- 23:05example.
- 23:09In here, I was using directly
- 23:12branch greater equal instruction.
- 23:15In here, I am using set less than
- 23:18operation. Set less than operation
- 23:20compares these two uh these S0 and T0
- 23:23registers.
- 23:24And if it is less than
- 23:26it makes T2 one.
- 23:30Otherwise, it makes T2 zero. Then in
- 23:33here, we can check whether T2 is zero or
- 23:36not
- 23:38by comparing it with the zero register.
- 23:40Because zero register X0 is all zero,
- 23:43always zero. Then we are comparing
- 23:45whether T2 is zero or not. It means that
- 23:48uh
- 23:49S0 is greater than Yeah, it checks the
- 23:51whether S0 greater than T0 or not.
- 23:57So, but this version is more preferable,
- 24:00right? Because it has less code.
- 24:02In here, I am executing one more code.
- 24:05Then one more code means that it it
- 24:07takes one more step, especially in the
- 24:09loop.
- 24:10Uh it takes one more instructions. So,
- 24:13this code, for example, if this loop
- 24:15runs 100 times,
- 24:17this code adds 100 cycle more because it
- 24:20has one more instructions. Since we are
- 24:22running the instruction cycle cycle, in
- 24:24each cycle I'm assume that in each cycle
- 24:27I am running one instruction.
- 24:29Then since there is a one more
- 24:30instruction in here, then it takes 100
- 24:33cycle more. So, for this reason, this is
- 24:36not good. If your code size is
- 24:38less than most likely,
- 24:41uh your
- 24:42program runs faster.
- 24:47But of course, there are some outlier
- 24:49cases for for it.
- 24:56RISC-V
- 24:57uh
- 24:58in for example in this five we are doing
- 25:00all addition operations in terms of
- 25:0332-bit if the processor is 32-bit.
- 25:08And in 32-bit operations generally the
- 25:11result can be 32-bit, right? Because
- 25:14if you are adding for example one one
- 25:17two one bit numbers, then result is two
- 25:19bit.
- 25:20It can for example if numbers is zero or
- 25:24one, then result can be two also and two
- 25:27can be represented by two bits.
- 25:30In a similar way, if you add two 32-bit
- 25:33numbers, generally result is normally
- 25:3533-bit because there must be a one
- 25:38overflow bit.
- 25:40Uh but RISC-V doesn't provide
- 25:42unsigned addition or instructions or
- 25:44overflow detection because it can be
- 25:46done with existing instructions.
- 25:49So for example in ARM architecture,
- 25:53assume there is a ARM 32-bit
- 25:55architecture,
- 25:56there is an addition operation
- 25:58and if this addition operation
- 26:02uh
- 26:03overflows, ARM has some flag bits and
- 26:06these flag bits are set so that you can
- 26:08check these flag bits and understand
- 26:10that this operation
- 26:12is overflowed.
- 26:14But in RISC-V, they don't need any
- 26:17necessity for it. So they didn't put any
- 26:19overflow checks and they are saying that
- 26:22if you want to check overflow, you only
- 26:25need to write your code in this way.
- 26:27In your code, you can explicitly check
- 26:30the overflow case. This is the RISC-V
- 26:32methodology. So instead of dealing it
- 26:34with in the hardware, they are saying
- 26:36that software software developers should
- 26:38should deal with them if they if they
- 26:41care. This is a good philosophy.
- 26:43For this reason, hardware becomes much
- 26:45simpler and simpler hardware means
- 26:47faster
- 26:49and it is also more efficient, more area
- 26:51efficient.
- 26:52And of course, you can detect the
- 26:54overflow very easily. For example, you
- 26:57can check, for example, detecting
- 26:59unsigned overflow, you can add two
- 27:01unsigned numbers
- 27:02and check
- 27:05in terms of, for example,
- 27:07uh you can say that branch less than
- 27:09unsigned comparison, you can do uh
- 27:11branch less than unsigned comparison and
- 27:13compare these two values.
- 27:15If then, for example, if you are adding
- 27:17two numbers and your result is less
- 27:20than, then it means that it overflowed.
- 27:24This is to detect unsigned overflow, and
- 27:27this is the way to detect signed
- 27:29overflow, for example. Signed overflow
- 27:31adds more
- 27:32instructions, for example. In here, in
- 27:35if you want to detect signed overflow,
- 27:37then you need to add, for example, three
- 27:39more instructions in
- 27:41unsigned overflow, you need to add one
- 27:43more instructions.
- 27:45But, most of the case, we don't care
- 27:47whether it is overflowed or not. For
- 27:49this reason, this is a good methodology
- 27:51to not
- 27:53check hardware hardware
- 27:56uh
- 27:57not put a mechanism
- 27:59that hardware checks this overflow. So,
- 28:01instead of that, software developers
- 28:03need to write this code explicitly.
- 28:08Is this point clear?
- 28:29Okay. So, we will start arrays.
- 28:42You know those C programming arrays?
- 28:44For example, in here, in memory, I have
- 28:47a five element array.
- 28:49And this five element array starts from
- 28:51this base address.
- 28:54Assume that it is five elements
- 28:57and each array element is 32-bit.
- 29:00And it starts from this base address.
- 29:03This one, this base address. So, in this
- 29:06base address, array zero corresponds to
- 29:08this, array one corresponds to this one,
- 29:10and you will see since this array is
- 29:1332-bit and this five element memory is
- 29:15byte addressable
- 29:16in
- 29:17each element
- 29:20our address is incremented by four 4-bit
- 29:24because it is byte addressable and each
- 29:25element is 32-bit. So, you will see it
- 29:29is 4-bit plus 4-bit plus 4-bit plus.
- 29:32So, this total array, if it is if there
- 29:35are five elements, then this total array
- 29:39is
- 29:4130 byte actually.
- 29:4320 byte, sorry.
- 29:455 * 4, it is 20 byte.
- 29:49So,
- 29:50in here, I have a C code and C code is
- 29:53defined an array and this array is in
- 29:56memory in this base address.
- 29:59And
- 30:00in this C code, we are doing this
- 30:02calculation.
- 30:03We are multiplying array zero with by
- 30:06two and array one by two and writing it
- 30:08back.
- 30:10So, since in here, in this example, in
- 30:12the previous examples, we were doing the
- 30:14computations all over registers, but now
- 30:17we are not using registers. We are using
- 30:19the memory addresses.
- 30:22First, in this case, we need to use load
- 30:24and store operations to access the
- 30:26memory locations. So, in order to get
- 30:28the data from memory, I need to use load
- 30:30operation. In order to store it back to
- 30:33memory, I need to use store operations.
- 30:38So, this is the RISC-V assembly code
- 30:41for this array operations.
- 30:44In here, you know, first I know that
- 30:48this array is stored in this address.
- 30:50The starting location of the array is in
- 30:53this address.
- 30:55And I know that compiler knows it
- 30:57because compiler is the tool that place
- 31:00the arrays while compiling the code
- 31:02because if this code has data also in
- 31:05it,
- 31:05then compiler knows its address and
- 31:08compiler assigns an address inside the
- 31:10memory region.
- 31:12And this is the assigned address for
- 31:14this array.
- 31:16So, in here,
- 31:18since this array address,
- 31:20this is 32-bit, address is also 32-bit.
- 31:23Since address is 32-bit, in order to
- 31:26load this array
- 31:27array address to S0 register,
- 31:30I cannot use I cannot do it in one
- 31:32instruction.
- 31:34I am using two instructions. In in the
- 31:37previous
- 31:39lecture, we we saw this concept. In this
- 31:42lecture, we are seeing the practical
- 31:44example of it. So, in here, I want to
- 31:46load the
- 31:48this base address of the array to S0
- 31:51register. So, how can do I do it? I need
- 31:54to run two instructions. One of them is
- 31:56load upper immediate. Load upper
- 31:58immediate takes this part
- 32:01of the instruction and load it to the
- 32:04upper 20 bits of S0 register.
- 32:08So, this is the 20-bit immediate.
- 32:11It gets 20-bit immediate and loads it to
- 32:15the upper bit portion of S0 register.
- 32:18And then for this remaining part, I am
- 32:21doing add immediate operation and this
- 32:23is the
- 32:2412-bit immediate.
- 32:26Then in this case, by running these two
- 32:28instructions, S0 becomes this address.
- 32:31So, I can get the address of the array
- 32:33in this way from S0.
- 32:37And then in order to access the first
- 32:39element of the array, then first element
- 32:42is in this location. By the way, this is
- 32:44the also first element means that the
- 32:46pointer of the array.
- 32:48Uh this is a concept belongs to the
- 32:50programming class.
- 32:52So, this array zero, which is the array
- 32:54pointer,
- 32:56uh
- 32:57this corresponds to the first element of
- 32:59the array.
- 33:00So, in order to load the first element
- 33:02of array, I am just running a load word
- 33:05command, and load word command in here
- 33:08takes the address of S0, adds S0 to it,
- 33:11so it points here.
- 33:14And loads this value to T1. This load
- 33:17word says that this is 32-bit load.
- 33:20And loads it to T1.
- 33:23Now, T1 keeps the first value of array,
- 33:26which is array zero.
- 33:28Then, in here, I am doing shift left by
- 33:31one bit. It means that in binary,
- 33:34multiply by two.
- 33:36I'm doing multiplication by two and
- 33:38storing the result to T1. Then,
- 33:41here,
- 33:42the turn is stored.
- 33:46This is the array address, array zero
- 33:50address. The C code says that
- 33:53I need to store it back to same
- 33:55location.
- 33:56So, I am running a store word operation
- 33:59in here.
- 34:00Then, store word address is S0 plus
- 34:03zero, which is this address still. And
- 34:07then,
- 34:08loads this T1 value to here. So, T1,
- 34:11which is the multiplied by two version
- 34:14of the
- 34:15of the initial value, then storing it
- 34:17back to the this location.
- 34:19And I'm doing it for the array one,
- 34:21also. In array one, doing the same
- 34:24operation, but this time, my index is
- 34:27four,
- 34:28because it's the array one.
- 34:30S0 plus four goes to this location, this
- 34:34one.
- 34:35Loading it, multiplying by two, and then
- 34:37writing it back to this location.
- 34:43I can do it in a for loop also, for all
- 34:45array elements also, right? I can write
- 34:48a for loop and in each
- 34:50for loop, I can multiply one element of
- 34:53array, for example, by two or do some
- 34:55operations on it. In here, there is an
- 34:57example code for it.
- 35:00Uh starting from zero to one 1,000,
- 35:04I'm loading the array.
- 35:06In here, this is the addressing.
- 35:09In here, for example, instead of using
- 35:11an immediate,
- 35:13compiler gives the code of or immediate,
- 35:15but doesn't matter. It's just immediate
- 35:18this
- 35:19with this one, so it means that I am
- 35:21keep I am placing this 12-bit value to
- 35:24here, so it forms 32-bit value still.
- 35:28It can use or immediate or add
- 35:30immediate, doesn't matter. It is It is
- 35:32giving the same value, which is the
- 35:34address of the array and storing it to
- 35:37the S0 location. So, S0 becomes this
- 35:39value.
- 35:40And then I have S1, which is the I
- 35:44value, and T2. T2 is the uh this
- 35:48constant value, 1,000 1,000.
- 35:51And then in the loop, I'm comparing
- 35:54whether I am
- 35:55greater equal to T2 value.
- 35:59If not,
- 36:00I am doing the multiplication in here.
- 36:02Uh not not multiplication.
- 36:05I am comparing the in I am computing the
- 36:08index in here. Since S1 is the byte
- 36:11offset,
- 36:13this this I,
- 36:15uh I am multiplying it by two to find
- 36:18the
- 36:19uh actual array index, because array is
- 36:2332-bit. Each element of the array is
- 36:2432-bit. In this case, in order to access
- 36:27the array actual location of the array,
- 36:30for example, if you want to access array
- 36:3210,
- 36:34you need to get base address of array
- 36:37plus 10 * 4 because each array element
- 36:41is 4 bytes. For this reason, you need to
- 36:44do this computation base address plus 10
- 36:46* 4. So, base address plus 40
- 36:50corresponds to array 10.
- 36:5210th element of two array.
- 36:54So, in here, I'm doing this computation.
- 36:57Then,
- 36:58I am finding the address of array. I'm
- 37:01adding it to the base address of the
- 37:02array, then loading array, then
- 37:06multiplying it by eight, then storing it
- 37:08back, and then increasing my I
- 37:11by one. Each time, I'm increasing the I
- 37:13by one.
- 37:15And then doing it for the array one,
- 37:17array two, until array 1,000.
- 37:20Is this example clear?
- 37:24Okay.
- 37:25For example, instead of int,
- 37:28this is same int. For example, assume
- 37:30that this is
- 37:32uh short.
- 37:35Short was 16-bit, right?
- 37:39Or in this case, instead of
- 37:42multiplying this index by two, I have to
- 37:46multiply
- 37:47So, sorry. Instead of multiplying it by
- 37:50four,
- 37:51it means that two shift left,
- 37:53I have to multiply it by two because
- 37:56each array element is two bytes. So, in
- 37:59here,
- 38:00we
- 38:02had to write one to here
- 38:04to multiply it by two. If this is byte,
- 38:08for example, assume that this is byte.
- 38:11There is no byte. It is char, for
- 38:13example. Char is 8-bit. If it is 8-bit,
- 38:17then there is no need to do any
- 38:18computation
- 38:19because each time my index is increased
- 38:22by one, so it it is increasing one byte
- 38:25each time.
- 38:26Is it clear?
- 38:32Okay.
- 38:37In there is also another concept RISC-V
- 38:40function calls.
- 38:43>> [clears throat]
- 38:44>> In a RISC-V there are two terminology,
- 38:46not in this not in RISC-V it in
- 38:49programming there are two terminology.
- 38:50One of them is caller and one one of
- 38:52them is callee.
- 38:54Uh caller is the calling function. If
- 38:56you are calling a function for example,
- 38:59for example you are calling a addition
- 39:00function, then you are the caller. You
- 39:02are running this function. For example,
- 39:04if main your main
- 39:07program calls the function of add, then
- 39:11main is the caller in here. So, the
- 39:15duty of the duties of the main is it
- 39:18passes the arguments to callee
- 39:21and jumps to callee. For example, in
- 39:23here main is
- 39:24calls this sum function, so it is the
- 39:26caller.
- 39:27And callee is the called function.
- 39:29In this case it is sum.
- 39:31Sum performs the function, it returns
- 39:34result to caller, returns the point of
- 39:36call. So, for example, after doing this
- 39:38computation,
- 39:40for example, I'm calling this sum
- 39:41function. After this after doing this
- 39:44computation, I'm returning back
- 39:46to the point of call, to this location
- 39:49to continue the program.
- 39:51And it has a
- 39:53duty that it must not overwrite
- 39:55registers or memory needed by the
- 39:57caller. For example, assume that this
- 39:59key code in here in main,
- 40:02this For example, in here I have also
- 40:04another variable
- 40:06named key for example.
- 40:08And this key is important and assume
- 40:10that this key is stored in X 4 for
- 40:13example.
- 40:16Whenever I call this sum function and
- 40:18inside this sum function during the
- 40:21computations while doing the
- 40:22computations, if I overwrite this X4,
- 40:26then when I
- 40:28go back to this main function again and
- 40:30assume that it this main function does
- 40:32some computation on this key in here.
- 40:36But since it is overwritten by this sum
- 40:38function, then this is a problem. For
- 40:40this reason, this function shouldn't
- 40:42change it.
- 40:43And there are some standards for RISC-V
- 40:46that the compiler needs to obey.
- 40:49Did you understand this problem? Is it
- 40:51clear?
- 41:00So, in here we did an introduction.
- 41:03Then in here
- 41:06there are function function call
- 41:08examples.
- 41:12In here I have a C code, and in C code I
- 41:15have a main function. This main inside
- 41:17this main function I am calling a
- 41:20function named simple.
- 41:22And then after returning from this
- 41:24function, I'm I'm calling this function,
- 41:26this simple function.
- 41:28And this simple simple function does not
- 41:30do anything meaningful. It just returns
- 41:33back to this point.
- 41:35I'm calling the simple, then inside this
- 41:38simple the first instruction that I
- 41:40encounter is return, so it just returns
- 41:42to here, back to here.
- 41:46So, when I compile this code,
- 41:49this is the resulted code.
- 41:52In here I have a main, and this main
- 41:55function, this is By the way, main is
- 41:57the
- 41:58introductory function for any program.
- 42:01It any pro-
- 42:03A- All programs starts with main, then
- 42:06calls to other functions.
- 42:09So, this main function calls the simple
- 42:13directly. This simple function
- 42:15So, this is call call routine. Jal
- 42:19Jal means that jump to this simple
- 42:22label, to this label.
- 42:24But, at the same time
- 42:26save the address of the return point.
- 42:29So, return point is here. So, it saves
- 42:31this address, this return point address
- 42:34to RA register. So, this address 0x34304
- 42:40is saved in register when I call this
- 42:43function.
- 42:44And then
- 42:47in here, I'm running this function. I
- 42:49jump this 15C location. And then in this
- 42:5315C location
- 42:55it is just returns. It is not doing
- 42:57anything useful. It just returns to RA
- 43:00location. Jump register RA means that
- 43:04jump back to RA location. So, what is
- 43:06the value of RA?
- 43:080x 304.
- 43:11So, 304 is here. So, it
- 43:14just returns to here, this
- 43:16at back.
- 43:18Is it clear, right? This is If you
- 43:19compile this C code
- 43:21its corresponding RISC-V assembly code
- 43:23is this one.
- 43:26So, in here, there is a void in here.
- 43:28This means that simple doesn't return a
- 43:31value. We are not returning any value.
- 43:33Sometimes in C you you want to return a
- 43:36value. For example, in this main, we are
- 43:37returning an integer.
- 43:39And this integer corresponds to error
- 43:43code of this program. If the this
- 43:44program runs healthy in a healthy way
- 43:46and finish in a healthy way, then this
- 43:48integer return value becomes zero. But,
- 43:51this this is specific to Windows, by the
- 43:53way. You don't need to know it.
- 43:56For example, this function returns a
- 43:57value, but this doesn't return any
- 43:59value.
- 44:01So, in here, we have a two instruction.
- 44:03We already see these so these functions,
- 44:06these instructions. Jal, simple, it
- 44:10jumps to simple label, but at the same
- 44:12time, while jumping, it saves the return
- 44:15address to RA register.
- 44:18And return address address is the PC
- 44:19plus four.
- 44:21If the PC is here, the PC plus four is
- 44:24here. So, it it saves this return
- 44:26address to RA register.
- 44:28And then jumps to the simple label.
- 44:30And another one is that it corresponds
- 44:34to this return instruction in C. It is
- 44:37jump register RA. Jump register RA says
- 44:40that just switch to RA.
- 44:43So, jump register RA means that you need
- 44:46to
- 44:47just go back to this location, RA
- 44:50location.
- 44:51And it is useful while returning from
- 44:53functions.
- 44:56Okay?
- 45:00In this slide, we will see the function
- 45:03call convention in RISC-V.
- 45:06Yeah. While calling a function, in here,
- 45:09you see we are using jump and link.
- 45:12Because jump means jumping, jumping to a
- 45:15label, but at the same time, I need to
- 45:16link. I need to know I need to register
- 45:19the my
- 45:21returning location
- 45:23after finishing this function. Because
- 45:25I'm going to a function, and when this
- 45:27function finish, I need to go back to
- 45:29main program, the color color function.
- 45:32So, in order to know it, I need to save
- 45:34my return address, and it means that
- 45:36linking.
- 45:38So, return from function, in order to
- 45:40return a function from a function, I
- 45:42need to jump register because this
- 45:45return address is stored in register RA
- 45:48during this jump and link.
- 45:50So, I'm just returning back to this
- 45:53location by using jump register.
- 45:59Also, in in
- 46:02RA has a specific meaning.
- 46:04Which RA is you see it
- 46:07register numbers. In RISC-V, we told
- 46:09that there are 32 registers
- 46:11and it has special meanings. You don't
- 46:14have to know them. You don't
- 46:16I'm not saying that you don't have to
- 46:17memorize them. You don't need to know
- 46:19them as a hardware developer, but it is
- 46:21beneficial for you to know them.
- 46:23For example, the important point for us
- 46:26as the hardware developer is the
- 46:28register number. X0 is always zero and
- 46:31rest is doesn't matter. They can be any
- 46:33value and there are 31 registers. But it
- 46:36has a special naming, special purpose.
- 46:40X0 is zero.
- 46:42X1 is RA, for example. So, when I say RA
- 46:45in here, it means that it is X1.
- 46:48And it is the special purpose of this X1
- 46:51register. The special purpose of this X1
- 46:54register is return address.
- 46:57But this is more This usage is more
- 46:59related more related to software guys,
- 47:03software developers, and compiler
- 47:05developers. They are also software
- 47:06developer, compiler developers. For us,
- 47:09it's not much important. But of course,
- 47:11in order to be familiar with the
- 47:13instruction set architecture, we are
- 47:14showing it in here.
- 47:17RA, it which is X1, has a special name.
- 47:21Also, arguments A0 and A7. What is A0
- 47:24and what A7? A0
- 47:27and A7, it is between X10 and X17.
- 47:31These are the arguments. They are also
- 47:33special meaning. If you are calling a
- 47:36function, then you are storing the
- 47:37arguments in A0, A1. You can use A0, A1,
- 47:41A2 for arguments. I will show argument
- 47:45example right now.
- 47:46And return value is You can use A0 for
- 47:50the return value. For example, you are
- 47:52calling a function name, call it sum.
- 47:55And this sum function gets two
- 47:56arguments.
- 47:58And in inside the sum function, you are
- 48:00adding these two arguments and returning
- 48:02a value. So, sum of these two values.
- 48:05Then
- 48:07arguments are A0 and A1. And return
- 48:11value, the sum of these A0 and A1 is
- 48:13stored in A0. This is a convention, by
- 48:16the way. You You don't have to follow
- 48:17this one. You can write
- 48:19For example, you can write an assembly
- 48:21code and you can return
- 48:23from in X 31, no problem. But this is
- 48:26the convention. The compilers generally
- 48:29follow this convention.
- 48:35So,
- 48:37in here, for example,
- 48:39I have a
- 48:40main function. Main function doesn't get
- 48:43any argument.
- 48:45And in main function,
- 48:47I have a Y variable. It is integer. And
- 48:50this main function calls diff of sums
- 48:53function. So, diff of sums function adds
- 48:57gets four arguments. For example, 3 2 4
- 49:005 in here.
- 49:02And this is the diff of sums function.
- 49:05It gets these four arguments and does
- 49:07this computation.
- 49:09It adds F to G and H to A and finds the
- 49:13subtraction of them. And this is the
- 49:15result and it returns this result.
- 49:20So, in here, what you will see is that
- 49:23these arguments are If you compile this
- 49:26C code, these arguments are stored
- 49:29stored in A0, A1, A2, and A3.
- 49:34And then this result returns in A0.
- 49:40Compiler follows this convention.
- 49:44Uh let's see the compiled code. This is
- 49:46the compiled code.
- 49:48In here, I have a main function. The
- 49:50program counter starts from here. It
- 49:52runs.
- 49:53At the beginning
- 49:55since these are the values, I am
- 49:58initializing this register as
- 50:01This is the initialization. A0 becomes
- 50:032, A1 becomes 3.
- 50:05And A0, A1, A2, and A3 are initialized.
- 50:10And then I am calling diff of sums
- 50:12function. Diff of sums function is
- 50:14called by jal. So, in here while calling
- 50:18diff of sums, I am saving the return
- 50:21address this address of this at to
- 50:24array.
- 50:25So, this
- 50:27array keeps the address of this
- 50:28instruction.
- 50:32And jal diff of sums
- 50:34I am calling to diff of sums.
- 50:37And when I call the function
- 50:39since in the convention I A0, A1, A2
- 50:43until A7 keeps the input arguments, I
- 50:47know that.
- 50:48And
- 50:49while writing this function, I know this
- 50:52this convention.
- 50:54So
- 50:56the compiler uses this A0, A1, A2, and
- 50:59A3 registers for the input arguments and
- 51:02computes some intermediate results
- 51:06and then computes the result and writes
- 51:08the result to A0 register, then returns.
- 51:13Return is
- 51:15returns to this location. So, this
- 51:17return
- 51:19changes the PC to this value to this
- 51:21instruction.
- 51:23And whenever you reach to this
- 51:25instruction, since in this convention I
- 51:27told you that return value is written to
- 51:29A0
- 51:31then
- 51:32I know that this A0 is
- 51:34the result of this function is stored in
- 51:37A0. So, starting from this location
- 51:41I know that A0 keeps the return value
- 51:44resulted value of diff of sums function
- 51:46so that I can use this value.
- 51:49But this is convention just
- 51:51compilers knows the compa- while giving
- 51:54can argument input argument to to a
- 51:57function, they are using A0 A7 between
- 52:01A0 and A7. For example, if they are
- 52:03using two only two argument is enough,
- 52:06then it only use A0 and A1. But this is
- 52:09just a convention.
- 52:10Yeah, so when you look at this code, it
- 52:12is
- 52:13reasonable.
- 52:15Right?
- 52:17Default sums, we I am jumping to this
- 52:19here. I am doing some computations over
- 52:22A0 A1 A2 and A3 and then writing the
- 52:25result to A0 then returning back to yeah
- 52:29here. And in here, I know that A0 keeps
- 52:32the the result of this function.
- 52:35Then I continue and use this value. This
- 52:38is just a convention.
- 52:42Yeah, you can inspect this
- 52:44code at home in detail, but it is it is
- 52:47very easy.
- 52:50What we are doing is that we are writing
- 52:52this C code
- 52:53and this C code
- 52:55translated to this binary.
- 52:58Compiler actually places Compiler uses
- 53:01this A0 A1 A2 and A3.
- 53:08In here, for example, while calling this
- 53:11function, I use A0 A1 A2 and A3 as the
- 53:14input argument, but also inside of this
- 53:16function, I overwrote these three
- 53:18registers T0 T1 and S3.
- 53:25And we can come to the previous our
- 53:28previous discussion before the break
- 53:30that what if in here, for example, I put
- 53:33some value over T0
- 53:36and this function overwrite this T0.
- 53:40And after returning back from this
- 53:42function to this point, this T0 is
- 53:45changed by this function.
- 53:47So, there is a problem right in here. If
- 53:50T0 is important for main, for example,
- 53:53and if diff of sums function changes
- 53:55this T0, then this is a problem.
- 53:59Because diff of sums I overwrote these
- 54:01three registers, T0, T1, and S3, which
- 54:04are What What is that? T0 is X5, T1 is
- 54:08X6, and S0 for example. S A0 is X8 for
- 54:12example in here. I changed these
- 54:14registers.
- 54:15This is the problem.
- 54:22In here,
- 54:28in here, I told you that there are
- 54:31seven arguments. Not seven, eight
- 54:34arguments between A0 and A7. What if,
- 54:36for example,
- 54:38a function would require more than seven
- 54:40arguments?
- 54:42For example, I am calling a function and
- 54:44this function requires more than
- 54:46seven arguments. Not seven, by the way,
- 54:49eight arguments because A0 A7, more than
- 54:53eight arguments. What What happens?
- 54:55In this case, we can use a stack. Stack
- 54:57means that a location in memory. So,
- 55:00because register is not enough for us.
- 55:03Register is There are 32 registers and
- 55:0731 of them are in use because X0 is
- 55:10always zero. So, our input arguments
- 55:14doesn't cannot fit into the register
- 55:16file because I need more than eight
- 55:19registers to pass my input arguments to
- 55:21function. Then, in this case, of course,
- 55:24I can use the memory. So, in memory, I
- 55:27can put two input arguments to memory,
- 55:29call a function, and this function can
- 55:31read the input arguments from memory.
- 55:34So, the place inside the memory that we
- 55:36use for this purpose is named as stack.
- 55:39So, we can use stack to temporarily
- 55:42store registers.
- 55:44So, in here we will see the stack.
- 55:52So, [clears throat] stack is the memory
- 55:53used to temporarily save variables. It
- 55:56is like stack of dishes, the last-in,
- 55:58first-out queue.
- 56:01So, in here for example, it is like
- 56:03dishes. So, you are putting the dishes
- 56:07top of each other, and while putting,
- 56:09you are putting the top,
- 56:11and while taking one, you are taking the
- 56:14one at the top.
- 56:16So, it's growing in this direction
- 56:19and shrinks in this direction. It's like
- 56:22these plates.
- 56:24So, it is a last-in, first-out queue in
- 56:27memory.
- 56:28It expands, it means that uses more
- 56:30memory when more space needed. It
- 56:32contracts, uses less memory when the
- 56:34space is no longer needed.
- 56:37So, it grows down from higher to lower
- 56:39memory address. So, while while going
- 56:43down, for example, its address is 0x8,
- 56:46for example.
- 56:47While growing downside, it
- 56:50decreases its address. I don't know why,
- 56:52but it is the convention. While if stack
- 56:55is growing,
- 56:57then its address is decrements.
- 57:03So, it grows down from higher to lower
- 57:06memory addresses. Stack pointer is SP,
- 57:10which points to the top of stack. By the
- 57:12way, SP is also a special register. So,
- 57:15SP corresponds to
- 57:18here, for example. What is SP? SP is X2.
- 57:22So, in compilers, generally compilers
- 57:24when compilers compile the C code,
- 57:28it uses X2 for SP, generally.
- 57:32Because it has a special meaning of
- 57:34stack stack pointer.
- 57:35It's a memory location by the way,
- 57:37memory address.
- 57:41So, SP points to top of stack. So, for
- 57:43example, assume that this is the top of
- 57:46stack and in top of stack I I put
- 57:49this value AB0001.
- 57:52And this is the address.
- 57:54Okay, SP is here.
- 57:57So, I want to put two words more to this
- 58:00stack. How I am putting it?
- 58:03I am just
- 58:04making room for two words. So, in the
- 58:08stack pointer is decremented by
- 58:12eight.
- 58:13So, it comes to here.
- 58:14To this point because it decrements by
- 58:17eight.
- 58:18So, if it is decremented by eight, it
- 58:20means that we are
- 58:22generating space for two words. And then
- 58:25I'm writing these two words to here.
- 58:30So, after decrementing here, the stack
- 58:32pointer was in here and then I changed
- 58:35it. It means that stack pointer is
- 58:37changed in this way. Immediate stack
- 58:39pointer stack pointer minus four minus
- 58:42eight, for example. So, stack pointer
- 58:44decremented by eight.
- 58:46Then, for example, I am doing load word,
- 58:50for example, sorry, store word.
- 58:53And I am storing this value to stack
- 58:56pointer
- 58:57>> [clears throat]
- 58:58>> four, for example, stack pointer four. I
- 59:00am
- 59:01storing this value, for example, to
- 59:03stack pointer four. And another I'm
- 59:06doing another store to stack pointer
- 59:09to this location. So, if I run two store
- 59:12word, then I can store two values to
- 59:15here. One of them is stack pointer plus
- 59:16four and other one is the stack pointer
- 59:18itself.
- 59:19Right? Is it clear?
- 59:23Okay, let's [clears throat] see an
- 59:23example for the stack pointer.
- 59:28So, stack usage in functions
- 59:32So, in here I have an example, the same
- 59:34example, diff of sums. And diff of sums
- 59:36uses this T0, T1, and S3 values because
- 59:40in here diff of sums overrides three
- 59:42registers, T0, T1, and S3.
- 59:47And
- 59:48>> [clears throat]
- 59:52>> uh in here, for example,
- 59:57this S3, T0, T1 diff of sums function
- 1:00:01changes this S3, T0, and T1.
- 1:00:05But assume that they are very important.
- 1:00:07So, before changing it,
- 1:00:09this this diff of sums function puts
- 1:00:12this S3, T0, and T1 registers to a
- 1:00:14stack. How it is putting? Assume that
- 1:00:17there is a stack in here.
- 1:00:20Yes, I can
- 1:00:21show in this picture.
- 1:00:23So, before this diff of sums function
- 1:00:25call,
- 1:00:28here is my stack pointer. The compiler
- 1:00:30assigned this value. The compiler is the
- 1:00:32stack corresponds shows the stack
- 1:00:34pointer. Actually, compiler assigns a
- 1:00:36pointer
- 1:00:37uh
- 1:00:38corresponds like the stack pointer.
- 1:00:40In here, I am
- 1:00:42decreasing the stack pointer by 12. So,
- 1:00:45I'm making space on stack to store three
- 1:00:48registers in here. So, stack pointer
- 1:00:51comes to the here, right? After
- 1:00:54minus
- 1:00:5512,
- 1:00:56the stack pointer comes to here.
- 1:00:58So, during call, stack pointer comes to
- 1:01:01here.
- 1:01:02And in each stack pointer location,
- 1:01:06this location, stack pointer, stack
- 1:01:07pointer four is here, stack pointer
- 1:01:10eight is here.
- 1:01:12I am storing these values, S3, T0, and
- 1:01:15T1, respectively in these locations. So,
- 1:01:18these
- 1:01:20registers are stored in here, okay?
- 1:01:23Until here there is no problem, right?
- 1:01:25It's just a RISC-V code.
- 1:01:28And here it is a function body. We did
- 1:01:32some computations in this function. It
- 1:01:34was default sums function. It was doing
- 1:01:38F plus G minus H plus I, this
- 1:01:42computation. And it was storing the
- 1:01:44result to S
- 1:01:463 register. This was S3 is the register
- 1:01:50that stores the result. And then I was
- 1:01:53writing it to A0 register. This A0
- 1:01:56register.
- 1:01:57Because A0 register was also return
- 1:01:59value.
- 1:02:00And normally in the previous version of
- 1:02:03the this code,
- 1:02:06I was doing no stack assignment. I was
- 1:02:08not writing these T0, T1, and S3 values
- 1:02:11to stack. I was just starting the
- 1:02:14computation and then returning the
- 1:02:16result. But in here,
- 1:02:20I am
- 1:02:22keeping a copy of T0, T1, and S3 in
- 1:02:25stack.
- 1:02:27In here. And
- 1:02:30since in here, during this function
- 1:02:32operation, since I overwrote these T0,
- 1:02:35T1, and S3 registers,
- 1:02:39I am just restoring them before
- 1:02:42returning to main.
- 1:02:44Did you understand this why we are doing
- 1:02:45it?
- 1:02:49And while restoring,
- 1:02:51in the same way
- 1:02:54after call,
- 1:02:56for example, in here, the stack in here,
- 1:02:59I saved these variables to here in
- 1:03:01stack. This is our stack. So, I stored
- 1:03:04this S3, T0, and T1 and did the
- 1:03:08computation in here. And while returning
- 1:03:10back, before going back to this main
- 1:03:13function,
- 1:03:15I am restoring these registers
- 1:03:17with the
- 1:03:19uh
- 1:03:20their original value. I am
- 1:03:22writing their original value back to
- 1:03:25register itself. So, I'm just getting
- 1:03:27this stack pointer plus eight, this S3,
- 1:03:30and
- 1:03:31this this value
- 1:03:33to it is a previous value of S3 and
- 1:03:36putting it to the S3 again back. I'm
- 1:03:39getting the previous value of T0 before
- 1:03:41function call and writing it to T0 and
- 1:03:45getting the previous value of T1 and
- 1:03:47writing it to T1. So, in here I'm
- 1:03:50restoring it.
- 1:03:51And then, when I return back to main,
- 1:03:55then
- 1:03:56these S3, T0, and T1 keeps their
- 1:03:59original values. It's like unchanged,
- 1:04:02nothing changed.
- 1:04:04Did you understand this point?
- 1:04:13So, in here, this is the call function.
- 1:04:15For example,
- 1:04:18now the point in here, for example,
- 1:04:23so
- 1:04:25in for example, in this main function,
- 1:04:29>> [clears throat]
- 1:04:29>> there are
- 1:04:3031 registers that can be used, right? X1
- 1:04:33to X31.
- 1:04:36And
- 1:04:38in main, I am running this diff of sums
- 1:04:41function and diff of sums function can
- 1:04:43change any value.
- 1:04:46Can use any register between X1 and X31.
- 1:04:50And before and after returning back,
- 1:04:53then any of these registers can be
- 1:04:55changed. In this case, should I
- 1:04:59uh
- 1:05:00keep a copy of all registers before a
- 1:05:02function call?
- 1:05:04Because it can change any register, and
- 1:05:06if I need this register, previous value
- 1:05:08of this register, then I should keep a
- 1:05:11copy of it. I should uh
- 1:05:13back up it.
- 1:05:16But in this case
- 1:05:18for example, in a similar way to this
- 1:05:20S3, T0, and T1 registers, should I for
- 1:05:24example store word between X1 X31? So,
- 1:05:29it means that running
- 1:05:3131 store word then doing the
- 1:05:33computation, and then restore all of
- 1:05:36these registers. Is it required?
- 1:05:39Because this function can use any of
- 1:05:41these registers. And if these registers
- 1:05:43are important for the caller
- 1:05:45then I need to restore them. I need to
- 1:05:47back up them and then restore them.
- 1:05:51This is not much possible because in
- 1:05:54every function called in this case, you
- 1:05:55need to call 31 store and 31 load while
- 1:05:59returning back.
- 1:06:00So, RISC-V
- 1:06:02puts a convention
- 1:06:04puts a standard and says that
- 1:06:08>> [clears throat]
- 1:06:08>> caller, for example saves any register
- 1:06:12any needed registers. For example, if
- 1:06:15you are a caller and you are a calling a
- 1:06:17function
- 1:06:18you need to save any needed registers.
- 1:06:21For example, RA,
- 1:06:23T0, T6, A A0, and A7. If you are using
- 1:06:28these one and these are important for
- 1:06:30you
- 1:06:31it says that caller needs to save it.
- 1:06:33So, before calling the function I need
- 1:06:36to save these registers. I need to do a
- 1:06:38backup.
- 1:06:39And I can I need to use the argument
- 1:06:41register as A0 and A7 and call the
- 1:06:45function and get the result return value
- 1:06:48from A0 and if you save any registers,
- 1:06:52any of these registers, for example,
- 1:06:55these registers are important for us. If
- 1:06:57and if I save any of them, I need to
- 1:06:59restore them after returning back.
- 1:07:02This is the
- 1:07:04caller function. Caller needs to do it.
- 1:07:06This is a standard. And what about the
- 1:07:09Call called one?
- 1:07:11Called one saves the registers that
- 1:07:14might be disturbed. For example, if call
- 1:07:17is
- 1:07:18is changing S0
- 1:07:20S1, this range, then it needs to save
- 1:07:23it.
- 1:07:24And while returning back, it has to
- 1:07:26restore them.
- 1:07:28But
- 1:07:30for call it
- 1:07:31it can change
- 1:07:33T0 T6 A0 A0 and A7. It is
- 1:07:38it is no problem to to change them.
- 1:07:41So, in this case, for example, if as a
- 1:07:43caller, for example, RA is important for
- 1:07:46me
- 1:07:46while calling a function, I need to back
- 1:07:49up it.
- 1:07:52The call saves the registers, this range
- 1:07:55registers, if they are using.
- 1:07:58Performs the function and put the
- 1:07:59results to A0, restore the registers
- 1:08:02that he saved. And then return this RA
- 1:08:06RA position. So, this is the conversion,
- 1:08:09actually.
- 1:08:10As a caller, for example, this is the
- 1:08:12non-preserved registers, T0 and T6, for
- 1:08:15example. So,
- 1:08:17if, for example,
- 1:08:20as a function, if I am using T0 register
- 1:08:23and T0 is important for the caller, then
- 1:08:26caller needs to save it. For example,
- 1:08:28this this specification conversion says
- 1:08:30it.
- 1:08:31But, for example, I am a call call. And
- 1:08:35if I am using S0 and S11, then I need to
- 1:08:39save it and restore it. This is a
- 1:08:41conversion.
- 1:08:44And the conversion is that you need I
- 1:08:47need to save and restore it in the
- 1:08:49memory region that is pointed by the
- 1:08:52stack pointer.
- 1:09:02Any question
- 1:09:04related
- 1:09:21>> [clears throat]
- 1:09:22>> So, this is the optimized function call.
- 1:09:25So, in here, for example,
- 1:09:28there is no need to save
- 1:09:30T0, T1.
- 1:09:31T0, T1 is not non-preserved register.
- 1:09:34So, if, for example, the caller function
- 1:09:36uses them, it is the duty of this caller
- 1:09:39function to save these registers.
- 1:09:41And in any function, while writing, for
- 1:09:43example, assembly code, you can use T0
- 1:09:46and T1, T2, this T register. It is named
- 1:09:49temp registers. You can use this temp
- 1:09:52register without
- 1:09:55backing up them or restoring them. No
- 1:09:57need. So, this is a convention because
- 1:09:59convention says that in a function,
- 1:10:02you can use T registers freely. No need
- 1:10:04to save them into the stack.
- 1:10:07So,
- 1:10:08the optimized function call, in this
- 1:10:10case, just use the non-preserved
- 1:10:12registers.
- 1:10:14Because why?
- 1:10:15If you are using non-preserved
- 1:10:17registers, these T registers, for
- 1:10:19example, then you don't need to save
- 1:10:21them to the stack and then restoring
- 1:10:23them to the stack. If the caller, for
- 1:10:26example, in here, the main
- 1:10:28uses them, then this is the duty of
- 1:10:31caller, main function, to save them to
- 1:10:33the stack.
- 1:10:34So, this is the convention.
- 1:10:36But generally, we don't pay much
- 1:10:38attention to it. The compilers does this
- 1:10:41job for us.
- 1:10:45So, non-leaf function is the function
- 1:10:47that calls another function.
- 1:10:49What should we do in non-leaf functions?
- 1:10:51For example, in here, I have a function
- 1:10:53one.
- 1:10:54And in this function one,
- 1:10:57uh am calling another function which is
- 1:10:59named as function two. So, I have a
- 1:11:01function
- 1:11:03and inside this function, I am calling
- 1:11:05another
- 1:11:07I am calling another function, G
- 1:11:08function for example, and in this
- 1:11:10function, I am returning back. So, it
- 1:11:12returns back to this point and this
- 1:11:14function returns back to the point that
- 1:11:16calls this F.
- 1:11:19Uh so, [clears throat]
- 1:11:20in here, this F is non-leaf function
- 1:11:22because it it return it calls another
- 1:11:25function.
- 1:11:27People say that it is non-leaf function.
- 1:11:30So, in here uh
- 1:11:33function one
- 1:11:35calls function two but before
- 1:11:38calling function two, there is an
- 1:11:40important register which is named RA.
- 1:11:45Actually, RA register keeps the value
- 1:11:47that function one will return back.
- 1:11:50So, this RA is important for us. So, in
- 1:11:53function one, before
- 1:11:55calling to function two register
- 1:11:57I am storing to RA
- 1:11:59to stack.
- 1:12:02In stack, for example
- 1:12:04for example, stack pointer is here. I am
- 1:12:06just
- 1:12:07making one
- 1:12:09uh
- 1:12:09one
- 1:12:11uh
- 1:12:12room in stack pointer
- 1:12:14and I'm writing
- 1:12:16to RA to here.
- 1:12:18This RA this RA is function one RA,
- 1:12:20okay?
- 1:12:21I'm writing it to the stack pointer in
- 1:12:23here.
- 1:12:24And then I'm calling function two. So,
- 1:12:26whenever I call function two
- 1:12:30this location, the return location,
- 1:12:32which is here, is written to RA.
- 1:12:36So
- 1:12:37in here, if I
- 1:12:39uh didn't save this RA register, then in
- 1:12:42this case, I would lose it. So, this is
- 1:12:45why I'm saving to to stack pointer.
- 1:12:48Because after some point, function one
- 1:12:51function function one will finish and I
- 1:12:53need to know to location where to where
- 1:12:56to return back.
- 1:12:58So, in here I'm calling function two and
- 1:13:00whenever I call this function two with
- 1:13:02jal instruction, then
- 1:13:05>> [clears throat]
- 1:13:06>> I am writing this return point inside
- 1:13:08the function one. I am writing this
- 1:13:11return point to the RA register. So, RA
- 1:13:14register is overwritten.
- 1:13:17And then
- 1:13:19>> [clears throat]
- 1:13:19>> for example,
- 1:13:20uh
- 1:13:23I'm assume that I call the function two
- 1:13:26and function two is in here.
- 1:13:29And while function two is returns,
- 1:13:32return means the jump register RA. So,
- 1:13:34I'm just returning back to this RA
- 1:13:36location, which is here.
- 1:13:38And then after returning here, I
- 1:13:40continue my program. I come back to
- 1:13:45jump function one and in function one,
- 1:13:48before returning from function one, I am
- 1:13:50restoring RA
- 1:13:52from its stack pointer. So, what is the
- 1:13:56RA? RA is the location that function one
- 1:13:59needs to return. So, I am just restoring
- 1:14:02RA value, then return to the point that
- 1:14:04call that function one is called from.
- 1:14:09Is it clear?
- 1:14:13So, in here we must preserve RA before
- 1:14:15function call.
- 1:14:17>> [clears throat]
- 1:14:19>> In here there is an example. I have a F1
- 1:14:22function. This F1 function calls
- 1:14:24function two. This is function two.
- 1:14:27So, in here for example, before
- 1:14:31before calling for this function two,
- 1:14:34I am
- 1:14:36opening a room.
- 1:14:37I am actually registering four five
- 1:14:39words in this stack. So, five words is
- 1:14:4220 byte. So, I am
- 1:14:46decreasing the stack pointer minus 20.
- 1:14:49And I am putting A0, A1, RA, and S S4,
- 1:14:54and S5 registers and keeping them into
- 1:14:56the stack. So, in this is the stack.
- 1:14:59Before call, this is the stack.
- 1:15:01And I am
- 1:15:03making a room of five words in stack and
- 1:15:07storing A0, A1, RA, S4, and S5 in in in
- 1:15:12in stack.
- 1:15:14And calling function two.
- 1:15:17This function two is called.
- 1:15:19And in this function two, I am adding
- 1:15:22another
- 1:15:24register to stack. In while calling this
- 1:15:27function two, my stack pointer
- 1:15:29was here in here.
- 1:15:31And also in here in this function two, I
- 1:15:34am adding another word to this stack
- 1:15:38stack. I'm keeping to S4 also. I I added
- 1:15:41S4 in here.
- 1:15:43And then while returning from F2
- 1:15:46function, I am just restoring this S4
- 1:15:49to here, then increasing the stack
- 1:15:52pointer. So, stack pointer
- 1:15:54just read this S4, then stack pointer
- 1:15:57comes back to this here.
- 1:15:59And jump return address.
- 1:16:01So, returning back to here.
- 1:16:05So, the the location that I called this
- 1:16:07function two. So, I return to this
- 1:16:09location. And after that in this
- 1:16:12location,
- 1:16:13>> [clears throat]
- 1:16:14>> I am also returning return address from
- 1:16:17stack pointer. So, it was in here. So,
- 1:16:20my stack pointer is here.
- 1:16:22Keeps here. So, RA is stack pointer plus
- 1:16:25eight, right? So, for example, I am
- 1:16:27loading stack pointer plus eight to RA.
- 1:16:31And then while returning from this
- 1:16:33function one, I can use this restored
- 1:16:35value of RA also.
- 1:16:39In here also while returning back in
- 1:16:41each for example, in each function, if
- 1:16:44you create a space in stack pointer, you
- 1:16:47need to give it back to. So, in here I
- 1:16:49am creating a space for five words.
- 1:16:51While returning back from function, I
- 1:16:53need to give this space back.
- 1:16:56Okay?
- 1:16:57And then jump to the return address.
- 1:17:00In here, and this return address is
- 1:17:02restored from the stack. Because you see
- 1:17:05in in
- 1:17:06while calling, because since I am
- 1:17:08calling a function, then inside the
- 1:17:10function, I am calling another function,
- 1:17:12this array is always gets overwritten.
- 1:17:15Whenever I call a function, I am
- 1:17:16overwriting the array. For this reason,
- 1:17:18I need to keep a copy of it in the
- 1:17:21stack, and while returning back, I I
- 1:17:24need to restore it back.
- 1:17:28Actually, these [clears throat] are the
- 1:17:28easy concepts. So, maybe in the in in
- 1:17:32home, you can inspect the slides one
- 1:17:34more time, and I think you can easily
- 1:17:35understand. Because it is they are
- 1:17:37trivial. They are very reasonable,
- 1:17:39logical uh facts.
- 1:17:49So, in here we can maybe give a break
- 1:17:52around
- 1:17:5312 minutes,
- 1:17:55then continue
- 1:17:57around
- 1:17:5814
- 1:18:0014
- 1:18:0140.
- 1:18:02We can continue at 14:40. We can give a
- 1:18:05break. Okay?
- 1:18:11So, we can continue with the recursive
- 1:18:13functions.
- 1:18:14The recursion means that the function
- 1:18:15calls itself.
- 1:18:18So, while converting to assembly code,
- 1:18:22which is the duty of the compilers,
- 1:18:28uh
- 1:18:28it in the first pass treat recursive
- 1:18:30calls as if it is calling a different
- 1:18:33function, and ignore the overwritten
- 1:18:35registers,
- 1:18:36then save restore registers on stack as
- 1:18:38needed.
- 1:18:40Actually, this is not the duty of the
- 1:18:41compiler while doing it.
- 1:18:43While writing an assembly while in to
- 1:18:47call recursively, you can follow this
- 1:18:49convention, but most likely we will not
- 1:18:50do it.
- 1:18:51So, for example, in here I have a
- 1:18:53recursive function func factorial n.
- 1:18:56It is n
- 1:18:59factorial. It means that n * n - 1 * n -
- 1:19:032.
- 1:19:04And
- 1:19:05in here
- 1:19:07if you write it as a recursive
- 1:19:10this is the function.
- 1:19:12So, I I have a
- 1:19:13C code. It is int factorial int n. And
- 1:19:17if n is less than one, less than or
- 1:19:20equal to one, it returns one. Otherwise,
- 1:19:23it returns n times factorial
- 1:19:25calls itself in here. n times
- 1:19:29the return value of this factorial and
- 1:19:32each time this factorial is called with
- 1:19:34n minus one.
- 1:19:37So, in if for example, if if we call
- 1:19:40factorial three, then it returns three
- 1:19:42times factorial two. So,
- 1:19:44factorial two returns two times
- 1:19:46factorial one.
- 1:19:48And then factorial one, this is the
- 1:19:51last step, last case in if it goes into
- 1:19:55this if statement and it returns one.
- 1:19:58So,
- 1:19:59in here factorial two one returns one,
- 1:20:01factorial two returns two times one.
- 1:20:04Because factorial two was two times
- 1:20:06factorial one, and factorial one returns
- 1:20:08one. Then factorial two returns two.
- 1:20:11Then if factorial two returns two, then
- 1:20:13factorial three returns three times two.
- 1:20:15Then it is six. Actually, this is three
- 1:20:17factorial.
- 1:20:19This is six.
- 1:20:20So, how
- 1:20:22compiler writes such a code?
- 1:20:24In this case, for example, in here I'm
- 1:20:27calling the factorial function. And
- 1:20:29factorial
- 1:20:31factorial makes makes space
- 1:20:34in stack pointer two words
- 1:20:36or two words.
- 1:20:38Minus eight means two words.
- 1:20:40And then it places A0 and RA.
- 1:20:43A0 is the input value input argument
- 1:20:47and RA is the return value
- 1:20:50in the stack pointer and then it does
- 1:20:52the computation in here. It
- 1:20:54compares this one with A0.
- 1:20:59It does this comparison.
- 1:21:01Branch greater than if it is greater
- 1:21:03than one then it jumps to S.
- 1:21:06So in S part it run it does this
- 1:21:09computation.
- 1:21:12It does [clears throat]
- 1:21:13it decreases by one since N was input
- 1:21:17value input value is stored in A0.
- 1:21:20It decreases A0 by one then calls this
- 1:21:23factorial again calls this function
- 1:21:25again.
- 1:21:27Okay?
- 1:21:28Otherwise if it is in this
- 1:21:31case if it is in here it just returns
- 1:21:36uh
- 1:21:37one. So A0 is becomes one in here and
- 1:21:40returns just returns one in here.
- 1:21:43It's jump returns to one directly.
- 1:21:48So it means that
- 1:21:49if it is in this condition it returns
- 1:21:52one and returns back to the RA.
- 1:21:55Because RA the return address.
- 1:21:58Okay?
- 1:22:01>> [clears throat]
- 1:22:05>> In here the important point is that
- 1:22:11each time
- 1:22:14in here RA is input the A0 is input
- 1:22:17input value.
- 1:22:19Uh
- 1:22:19when I call this factorial I am saving
- 1:22:22this input value to stack and I am
- 1:22:24saving the return address to this stack.
- 1:22:27And while returning back from this
- 1:22:30factorial in here in here it returns,
- 1:22:34I need to restore them
- 1:22:36here.
- 1:22:38Because I'm calling this function and
- 1:22:39this function has a array value. When I
- 1:22:41call this function, this function has a
- 1:22:44array value and when I call it again,
- 1:22:49I have another array value. If I this
- 1:22:51array writes to over this array, then I
- 1:22:53lose this value. For this reason, at
- 1:22:55each time I am storing this array values
- 1:22:58to this the stack pointers and while
- 1:23:00returning back from this factorial
- 1:23:02function, I am restoring them. I need to
- 1:23:04restore them.
- 1:23:06This is the logic behind it.
- 1:23:12So,
- 1:23:14it means that and in here also while
- 1:23:16returning back, you need to add stack
- 1:23:19you need to restore the stock stack
- 1:23:20pointer because in here when you call a
- 1:23:22function, you are using two words in
- 1:23:24stack pointer and you need to give it
- 1:23:26back while returning back.
- 1:23:36>> [clears throat]
- 1:23:36>> So,
- 1:23:39if you have a question, we can look at
- 1:23:41here, but otherwise it is I advise you
- 1:23:44to inspect this code at home.
- 1:23:46Definitely you you have to look at it.
- 1:23:49For example, look at these codes and run
- 1:23:51it step by step at home and you can
- 1:23:54understand the reasoning behind it.
- 1:23:58By any questions, you can ask in Turkish
- 1:24:00also we can we can look at it.
- 1:24:10And this is an
- 1:24:13uh call in here.
- 1:24:15This is same factorial function. This is
- 1:24:17the code. It has S and in here I have
- 1:24:21now I give
- 1:24:23memory addresses in here. This is the
- 1:24:24address of the instructions. For
- 1:24:26example, this factorial is stored at
- 1:24:283,500, this location. This is the memory
- 1:24:31location of factorial.
- 1:24:33So, while returning,
- 1:24:35while calling this jal factorial,
- 1:24:39at that point, I am saving this return
- 1:24:42address, which is the return address,
- 1:24:44because I will call this factorial
- 1:24:46again. And while this factorial returns
- 1:24:48back, it needs to return back to here.
- 1:24:51Okay? So, I'm saving this return address
- 1:24:53to here, and this is the return address.
- 1:24:550x 8528.
- 1:25:05So, this is the return address when
- 1:25:06factorial is called recursively.
- 1:25:09So, this is the stack station while
- 1:25:11calling the factorial. So, when I call
- 1:25:14the factorial three,
- 1:25:15then
- 1:25:17first,
- 1:25:20I am writing this a0 and ra
- 1:25:24in after recursive call. I am saving the
- 1:25:27ra also in here.
- 1:25:29And then,
- 1:25:32this is
- 1:25:35No, factorial three is called, right?
- 1:25:38Factorial three is called, so I am
- 1:25:40saving this a0 and return address this
- 1:25:43factorial three. This factorial three is
- 1:25:45saved. Factorial three is called.
- 1:25:48Okay?
- 1:25:49I'm saving this input a,
- 1:25:51which is a0, three, and return address
- 1:25:54this factorial three. The the return
- 1:25:56address
- 1:25:57when I called this factorial three,
- 1:25:59okay?
- 1:26:02And this factorial three
- 1:26:04does this operation, three times
- 1:26:06factorial two, right?
- 1:26:07And when I call this factorial two,
- 1:26:10I have to save previous return address.
- 1:26:13So, I am saving this previous return
- 1:26:15address.
- 1:26:16And at the same time, I am saving this
- 1:26:18A02 in here. So, I am at each call
- 1:26:22I am I am saving these
- 1:26:25variables to the to inside the stack.
- 1:26:27So, in factorial two, I am saving this
- 1:26:30register, and this factorial two calls
- 1:26:32factorial one, because factorial two is
- 1:26:35two times factorial one.
- 1:26:37And when I call this factorial one, I am
- 1:26:40also saving these values.
- 1:26:45And while returning back, this
- 1:26:48For example, now I called factorial one.
- 1:26:51So, factorial one returns back one. So,
- 1:26:54RA is the location that I I will return
- 1:26:57here. So, RA I am just returning back to
- 1:27:00RA.
- 1:27:01But at that point,
- 1:27:03I need to restore the RA
- 1:27:05from stack and return back to here. And
- 1:27:08I need to restore it from stack and
- 1:27:10return back to here. Because every time
- 1:27:12when I call a function by using JAL, I
- 1:27:15am overwriting RA. So, before
- 1:27:18overwriting
- 1:27:19over it before overwriting it, I need to
- 1:27:23back up it in in the stack.
- 1:27:26And then,
- 1:27:28I need to restore it.
- 1:27:30And this is the way to do it. While
- 1:27:33while [clears throat] calling the
- 1:27:34function,
- 1:27:35I am writing this A0 and RA.
- 1:27:38And in another call, I am writing it
- 1:27:40back again in stack also in again.
- 1:27:44And while returning back to stack, I am
- 1:27:46reading them.
- 1:27:48In the reverse order that I put.
- 1:27:51It's like
- 1:27:52first thing
- 1:27:55Actually, it is a LIFO structure, last
- 1:27:57in first out structure.
- 1:28:00So, while calling, I am adding these
- 1:28:01registers. And while returning back,
- 1:28:03because it is recursive,
- 1:28:05I am calling calling calling. And after
- 1:28:08the end, I am returning back from the
- 1:28:10recursive functions. Then, I am
- 1:28:12returning back to here by by reading
- 1:28:14them from the stack.
- 1:28:19Is this concept clear? This This example
- 1:28:21is long because for this reason I didn't
- 1:28:24go step-by-step over the instructions.
- 1:28:27Uh but this is a homework for you. You
- 1:28:29need to follow.
- 1:28:31It [clears throat] is a good practice
- 1:28:32for
- 1:28:33uh for
- 1:28:35to understand the instruction set
- 1:28:36architecture. But of course, this is
- 1:28:38these concepts are not must for you. It
- 1:28:40is just to be familiar with the
- 1:28:42instruction set architecture.
- 1:28:49So, there is also another concept named
- 1:28:51pseudo instructions.
- 1:28:54Ahem. Pseudo [clears throat]
- 1:28:54instructions are not the actual RISC-V
- 1:28:56instructions, but they are often
- 1:28:59uh more convenient for the programmer.
- 1:29:01So, you For example, you can compile a
- 1:29:03program, and in the compiled uh assembly
- 1:29:06code, you can see some instructions, but
- 1:29:09these instructions are not real.
- 1:29:11They don't exist.
- 1:29:13Uh actually, they corresponds to another
- 1:29:15instruction, actual instruction, but
- 1:29:18people use them in assembly language to
- 1:29:21make it assembly more readable. For this
- 1:29:23reason, they are using the pseudo
- 1:29:25instructions.
- 1:29:27So, as in in that point, assemble
- 1:29:30assembler converts them to real RISC-V
- 1:29:32instructions. For example, RISC-V has
- 1:29:34four jump pseudo instructions. For
- 1:29:36example, jump immediate.
- 1:29:39This jump immediate, for example, says
- 1:29:41that jump to this immediate,
- 1:29:43but normally, it uses jump instructions,
- 1:29:48but jump instruction uh saves
- 1:29:52the return address to X0. That saving
- 1:29:55something to X0 means that nothing
- 1:29:57saved.
- 1:29:58Because in jump immediate says that jump
- 1:30:01to a a location, but don't save
- 1:30:03anything. Don't save the return address.
- 1:30:06So,
- 1:30:07return address is like saving to X0.
- 1:30:09Save saved in X0, but X0 doesn't keep
- 1:30:12anything because X0 is always
- 1:30:14corresponds to zero.
- 1:30:17So, this is [clears throat] the pseudo
- 1:30:18instruction actually for jal X0
- 1:30:21immediate. For example, jal immediate
- 1:30:23jump and link. This time I have to save
- 1:30:26the return address. So, this return
- 1:30:28address saved at R R0 RA register.
- 1:30:32So, this corresponds to this one. These
- 1:30:34These are Look at it. These are two
- 1:30:36different instructions, like two
- 1:30:38different instructions, but they are all
- 1:30:40jal instruction. These two are
- 1:30:42corresponding to jal instruction, but it
- 1:30:44is easier. For example, when you look at
- 1:30:46the assembly code,
- 1:30:47this is the ja ji je For example, je
- 1:30:51immediate, you can read it, but its
- 1:30:53actual corresponds to this one. But,
- 1:30:55since this is more readable, more
- 1:30:57friendly to understand, or compiler
- 1:31:01pulls these codes. But, these are the
- 1:31:02pseudo instructions, not real. It's
- 1:31:04actual corresponds both jal.
- 1:31:07For example, jump register ARF, it is
- 1:31:10named as jump and link register X0 ARS0.
- 1:31:14Since return address has no meaning, I'm
- 1:31:17just storing it at to X0. It means that
- 1:31:20we are not storing it because X0 is If
- 1:31:23we are writing trying to write to X0, we
- 1:31:25are not writing.
- 1:31:26The
- 1:31:27processor does not write to X0. X0 is
- 1:31:30always zero.
- 1:31:32But, it comes to ARS location. Return.
- 1:31:35This is function return. It is jump
- 1:31:37register RA.
- 1:31:41So, [clears throat] return means that
- 1:31:42jump register RA.
- 1:31:44For example, in the compiled program, in
- 1:31:46the compiled function, you can see just
- 1:31:48a return, but this return means that
- 1:31:51there is no return instruction in this
- 1:31:52file. When you look at the instruction
- 1:31:54set architecture manual, there is no
- 1:31:56return instruction. This just
- 1:31:58corresponds to jump register RA. It
- 1:32:01means that jump register to array
- 1:32:03register but does not store anything
- 1:32:05this instruction.
- 1:32:10So [clears throat] for example there is
- 1:32:11a pseudo call instruction. Call
- 1:32:13instruction says that go to this
- 1:32:15location.
- 1:32:17Go to this 32-bit location to this
- 1:32:2032-bit address but in RISC-V it is
- 1:32:22impossible to implement it in one
- 1:32:24instruction because the maximum
- 1:32:26immediate field is 20-bit. In this case
- 1:32:30uh this call
- 1:32:32function actually is
- 1:32:34consists of two different functions.
- 1:32:37One of them is add upper immediate to PC
- 1:32:39and other one is the jump and link
- 1:32:41register.
- 1:32:42So this call
- 1:32:44corresponds to two instructions
- 1:32:46actually.
- 1:32:48But this is pseudo instruction. If you
- 1:32:49write it in assembly then your assembly
- 1:32:52becomes more readable.
- 1:32:55So in here there is a table. You can see
- 1:32:58some pseudo instructions and it is
- 1:33:00actually RISC-V correspondence. You can
- 1:33:02check it.
- 1:33:03Uh there is no need to memorize it.
- 1:33:06For example there is no move instruction
- 1:33:08in RISC-V. How can we do move
- 1:33:11instruction? It is just add immediate
- 1:33:13for example. If you want to move S3 to
- 1:33:15T5 for example you can use
- 1:33:17uh
- 1:33:18add immediate T5 S3
- 1:33:22for example zero. Or you can do it with
- 1:33:25add instruction. Add T5 S3 X0. X0 is
- 1:33:29always zero. You can do it with or for
- 1:33:32example and or with X0 because if you
- 1:33:36or the register with itself and then
- 1:33:40write it back to another location then
- 1:33:42it is just move move operation. Move
- 1:33:44operation moves this S3 to T5.
- 1:33:47There is not instruction for example but
- 1:33:49in actual there is not instruction in
- 1:33:51RISC-V in RISC-V. You can do it by using
- 1:33:54XOR immediate.
- 1:33:56So for example no instruction is writing
- 1:33:59zero to zero plus zero, for example.
- 1:34:01Because we cannot write zero, then this
- 1:34:03is a no operation.
- 1:34:07So, these are all actual
- 1:34:08correspondences, but these are the
- 1:34:10pseudo instructions. They are not
- 1:34:12ex- They are not real not real, but
- 1:34:15they are you can see them.
- 1:34:18Uh this is the last concept.
- 1:34:21Compiling, assembling, and loading
- 1:34:22programs.
- 1:34:27In
- 1:34:28RISC-V, we told that instructions and
- 1:34:32uh instructions are 32-bit, and
- 1:34:34instructions and data are stored in
- 1:34:36memory in RISC-V.
- 1:34:38When we compiled it, uh
- 1:34:41as a compiled
- 1:34:43code,
- 1:34:44there are instructions in it and data,
- 1:34:46also. You can put data in it.
- 1:34:50So,
- 1:34:54for example, in here we have a assembly
- 1:34:56code, compiled code, and it is machine
- 1:34:57code correspondence. So, this
- 1:35:00uh machine code is loaded to the main
- 1:35:02memory, and then main memory
- 1:35:05runs this code one by one. Assume it is
- 1:35:09one by one. By the by time, we will see
- 1:35:12architectures that runs the codes two by
- 1:35:15two, four by four. Supers- They are
- 1:35:17named as superscalar architectures.
- 1:35:19For example, a machine can run four
- 1:35:22instructions at a time immediately at
- 1:35:23the same time.
- 1:35:25But, assume that it increases the PC by
- 1:35:27one by, and each time it runs an
- 1:35:30instruction.
- 1:35:32So, to run a new program, we simply
- 1:35:34store the program in memory. So, we we
- 1:35:36are writing a code in C, compiling it.
- 1:35:39It's the assembly code. This assembly
- 1:35:41code converted to machine machine code,
- 1:35:44and this machine code is compiled
- 1:35:46written to the main memory, and in main
- 1:35:48memory, we have a program counter.
- 1:35:50And each time, we are reading this main
- 1:35:53memory region, this instruction from
- 1:35:55main memory and
- 1:35:57running it in the in the processor
- 1:36:00and doing the computation.
- 1:36:01So, in program execution pro- processor
- 1:36:04fetches the list instruction from memory
- 1:36:07in sequence
- 1:36:08one by one.
- 1:36:09And then we are performing the specified
- 1:36:12operations.
- 1:36:14So, for example, in here I put a example
- 1:36:17for a more complex C code. In here I
- 1:36:19have a main code and in this main I'm
- 1:36:22calling function, this function, and it
- 1:36:25has F and G arguments.
- 1:36:27And this function does this operation
- 1:36:31and calls itself again.
- 1:36:34So, if for example in this function, if
- 1:36:36B is less than zero,
- 1:36:38then it returns A plus B, otherwise it
- 1:36:41returns A plus
- 1:36:43function A B minus one. So, it calls
- 1:36:46itself again.
- 1:36:47But at that time B is decreased by one.
- 1:36:51So, when you look at here,
- 1:36:54>> [cough and clears throat]
- 1:36:54>> so
- 1:36:59this is the main main.
- 1:37:02So,
- 1:37:03this is the function actually. This is
- 1:37:05the function implementation. The
- 1:37:06function first in This is the function
- 1:37:08implementation. How function is
- 1:37:10implemented in machine code in RISC-V
- 1:37:12assembly.
- 1:37:13At the beginning function makes room for
- 1:37:16the forward
- 1:37:17as stack pointer. Then it pulls these
- 1:37:20values to stack pointer.
- 1:37:22Does some move operations, for example,
- 1:37:24it it moves A0 to S0. And does some
- 1:37:27computations, you can inspect them at
- 1:37:29home. I don't
- 1:37:31go to the detail.
- 1:37:32And in here there is a jump location,
- 1:37:35branch greater equal zero, then it it
- 1:37:38jumps back to this location.
- 1:37:43So,
- 1:37:45this is the location that called this
- 1:37:48function by the way. This is most likely
- 1:37:50main location main function because this
- 1:37:52returns or this returns to main function
- 1:37:56but otherwise it continues. In here
- 1:37:58there is a return main function.
- 1:38:03Otherwise by the way yeah no this is
- 1:38:06this is not this is comparison this is
- 1:38:08not return. This is comparison this
- 1:38:10branch greater than equal this
- 1:38:11comparison.
- 1:38:13And if this comparison
- 1:38:15branch greater than equal zero
- 1:38:17if true then it does this operation and
- 1:38:20returns. Does this A plus B operation
- 1:38:22and returns. Otherwise it jumps to here.
- 1:38:26This function plus zero X 28. This is
- 1:38:29function address
- 1:38:31and after zero 28
- 1:38:34zero X 28 is most likely here and in
- 1:38:36here it does this operation. And in this
- 1:38:39operation we are calling this function
- 1:38:41again in here.
- 1:38:43We are calling this function again.
- 1:38:47After calling this function again this
- 1:38:50function is called again. I am putting
- 1:38:51another set of variables in stack doing
- 1:38:54this operation again and calling again
- 1:38:57function and after some time
- 1:39:00this function returns. Whenever this
- 1:39:01function returns it continues from this
- 1:39:03region here
- 1:39:05and then jumps to back
- 1:39:08to here actually the the
- 1:39:10to here and then gets another return.
- 1:39:14And then after that returns this value
- 1:39:17and returns it to here.
- 1:39:20So
- 1:39:22maybe in here in in four five minutes it
- 1:39:25is not
- 1:39:26much
- 1:39:29possible to understand this example but
- 1:39:31definitely you you you need to inspect
- 1:39:33it at home. You can inspect it one by
- 1:39:35one running one by one.
- 1:39:37So this is the main function. So this
- 1:39:40main function is just also putting some
- 1:39:42value to the store.
- 1:39:46And then calls to the function, for
- 1:39:47example, in here. And after that, it
- 1:39:49returns and also main function returns
- 1:39:52itself.
- 1:39:53This is just compiled version of this C
- 1:39:56and assembly code.
- 1:40:01So, in here the there is another concept
- 1:40:04of global pointer. We mentioned about
- 1:40:06stack pointer.
- 1:40:08Uh global pointer is also another
- 1:40:11uh another region in memory. And in
- 1:40:14global pointer, as name is global, it
- 1:40:17keeps the global variables. For example,
- 1:40:19in a C code,
- 1:40:22if you write some variables like also
- 1:40:25also outside of the main and these
- 1:40:27functions inside file in in your C code
- 1:40:30file, but outside of these functions,
- 1:40:33main and function, they are the global
- 1:40:35variables. And these global variables
- 1:40:37are stored in
- 1:40:39GP location.
- 1:40:41So, compiler used this GP variable to
- 1:40:44store the global variables. And global
- 1:40:45variables are the variables stored
- 1:40:47outside of the
- 1:40:49functions in C code. This is a knowledge
- 1:40:51from C, by the way, not related to this
- 1:40:53class. This is a C C knowledge.
- 1:40:56So, for example, in here, we are storing
- 1:40:59F and G in this global pointer plus
- 1:41:03minus 9 on 945, for example. And other
- 1:41:06one is minus 940 in this global pointer
- 1:41:09location. But,
- 1:41:11you don't need to
- 1:41:14yeah, know much about them because
- 1:41:16compiler does this assignments, memory
- 1:41:18assignments. You need to know the just
- 1:41:20the meaning of GP. And GP is most likely
- 1:41:23it was X3, most likely. I don't
- 1:41:25remember, but it it might be X3. So, it
- 1:41:28is a register and it has a special
- 1:41:31meaning of global pointer in this file.
- 1:41:38So, you can inspect these these examples
- 1:41:40in detail at home.
- 1:41:44So, when you compile a program, the
- 1:41:46programs has some symbol tables.
- 1:41:50Uh, most likely I have example in here.
- 1:41:53Uh, no, we don't have example, but no
- 1:41:56problem. Uh, text we previously
- 1:41:59mentioned about it. Text means that code
- 1:42:01instructions. Data means that if you if
- 1:42:04I have data, for example, I have a array
- 1:42:07and I define this array values as
- 1:42:09constant in this C code, then this array
- 1:42:12elements goes into the data segment.
- 1:42:16For example, in here
- 1:42:17uh, it says [clears throat] that
- 1:42:19the instructions are placed at this
- 1:42:21address 10074
- 1:42:24in memory. And data is placed in 115E0
- 1:42:28location in memory. It is not related
- 1:42:31with us. Compiler does this job.
- 1:42:33Compiler
- 1:42:34knows to
- 1:42:35CPU, its memory structure, and it places
- 1:42:38the data and text section to there.
- 1:42:41For example, text For example, function
- 1:42:43three function, it is a function, it's a
- 1:42:45instruction. So, instruction means that
- 1:42:48text, for example.
- 1:42:50So, compiler says that
- 1:42:52the function is size of the function is
- 1:42:543C. And it is placed at this location.
- 1:42:58And there is also main function, and its
- 1:43:00size is 34 34, and it's placed in this
- 1:43:04uh, address. [clears throat]
- 1:43:06And there is also BSS section. This is
- 1:43:08also related with data. This is global
- 1:43:10data, for example, FGY, and they are
- 1:43:13stored in here.
- 1:43:14But, this symbol table is generated by
- 1:43:17the compiler. Also, you can say that,
- 1:43:19for example, I want to put this text in
- 1:43:22this memory region, you can also give
- 1:43:23compiler a linker file, and you can do
- 1:43:26it. But, compiler this this does this
- 1:43:29job automatically.
- 1:43:30And shows the where the data and
- 1:43:33instructions are stored and global
- 1:43:34variables are stored. And at the end
- 1:43:37this
- 1:43:39program, the program that you compile
- 1:43:42are stored in memory in this way. And
- 1:43:44this is the memory layout, for example.
- 1:43:46In here, for example, I have
- 1:43:48instructions.
- 1:43:49This is the instruction region, for
- 1:43:51example, text region, by the way.
- 1:43:53This is the address, by the way. This is
- 1:43:55the addresses for the text region.
- 1:43:58And this corresponds to be here. And for
- 1:44:00example, here is global pointer. So, you
- 1:44:03all the compiler says that this address
- 1:44:06keeps the global pointer stack. For
- 1:44:09example, it C says that this is the
- 1:44:11stack pointer. So, your stack addresses
- 1:44:14in here. So, whenever while using stack,
- 1:44:18you are using from here.
- 1:44:19This is the region in memory that you
- 1:44:21are using stack.
- 1:44:23And this is the text, for example. The
- 1:44:25And PC, for example, starts from here.
- 1:44:27It says that PC needs to jump to here.
- 1:44:30For example, operating system, whenever
- 1:44:31you double click, for example,
- 1:44:33PowerPoint, then operating system
- 1:44:35changed the PC
- 1:44:37as the first instruction of PowerPoint.
- 1:44:41So, PC comes to here, for example, and
- 1:44:43runs in here. And sometimes it jumps to
- 1:44:46somewhere. And in some instructions, for
- 1:44:48example, it loads data from this stock
- 1:44:50pointer or loads this load any data from
- 1:44:53global pointer. This is the way that how
- 1:44:55programs run in a processor. It is not
- 1:44:58specific to RISC-V. In all instruction
- 1:45:00set architectures, it runs in this way.
- 1:45:04And so, this is the last slides.
- 1:45:07So, RISC-V design principles,
- 1:45:09RISC-V follows the simplicity rules.
- 1:45:12As you can see,
- 1:45:14the location of RS1 is always same
- 1:45:18irrespective of the instruction type.
- 1:45:20The location of RS2, function 7,
- 1:45:22function 3, all same. So, RISC-V follows
- 1:45:26the simplicity. So, everything is
- 1:45:28consistent. Same number of operands. So,
- 1:45:31easier easier to encode and handle it on
- 1:45:34hardware.
- 1:45:36So, RISC-V also includes only simple and
- 1:45:38commonly used instructions. For example,
- 1:45:40I mentioned that RISC-V has no sub
- 1:45:42immediate instruction because I can
- 1:45:44implement sub immediate instructions
- 1:45:46instruction by add immediate easily.
- 1:45:48Just negating the immediate. So, RISC-V
- 1:45:53doesn't have any sub immediate
- 1:45:55instruction.
- 1:45:56In this way also, since RISC-V is
- 1:45:58simpler hardware to decode and execute
- 1:46:00instructions can be simple, small, and
- 1:46:02fast.
- 1:46:03And more complex instructions performed
- 1:46:06using multiple simple instructions. For
- 1:46:08example, for overflow, we can put some
- 1:46:11couple of instructions and
- 1:46:13form this
- 1:46:15overflow check
- 1:46:17by using couple of instructions.
- 1:46:20So, we can All instructions are simpler,
- 1:46:22by the way.
- 1:46:23So, since for this reason it's named as
- 1:46:26reduced instruction set computer, RISC.
- 1:46:30Other architectures such as Intel x86
- 1:46:34are CISC, complex. Because in x86, I
- 1:46:37told that instructions are variable. It
- 1:46:39is between 1 or I think 17 bytes
- 1:46:43between.
- 1:46:44So, for example, one instruction is 1
- 1:46:45byte. One instruction can be 4 byte. So,
- 1:46:49their decoding all all are different.
- 1:46:52So, this is complex. For this reason, it
- 1:46:54is complex instruction set architecture.
- 1:46:58So, for this reason, since RISC-V is
- 1:47:01smaller, its decoding is simpler, it is
- 1:47:03faster.
- 1:47:05Always, for example, it has using either
- 1:47:09three register or two register operands.
- 1:47:11For example, in Intel, it changes. Maybe
- 1:47:13it can use four, five registers.
- 1:47:15Sometimes it is doing some For example,
- 1:47:17it can do addition between a register
- 1:47:19and a the
- 1:47:20In RISC-V, if you want to do
- 1:47:23uh addition between a memory region and
- 1:47:25a register, you need to load this memory
- 1:47:28to a register, and then you need to do
- 1:47:30computation between the registers. You
- 1:47:32cannot do a computation
- 1:47:34in RISC-V, for example, there is no such
- 1:47:36an instruction at
- 1:47:38for example, X2, X3
- 1:47:41uh address, for example, address
- 1:47:440x FF8. For example, there is no such
- 1:47:47instruction in RISC-V. But in, for
- 1:47:49example, Intel, there is such
- 1:47:51instructions. You are getting a register
- 1:47:53and getting a getting a value from
- 1:47:55memory and adding them, putting it to
- 1:47:57the X2. In RISC-V, if you want to get a
- 1:48:00if you want to access memory, the only
- 1:48:03way is load or store
- 1:48:05to access. So, for this reason, RISC-V
- 1:48:08is simpler instructions.
- 1:48:09And this simplicity at the end, in turn,
- 1:48:13provides faster architectures. For this
- 1:48:16reason, it is very good opportunity
- 1:48:19uh
- 1:48:20for right now to build processors in
- 1:48:22RISC-V. And it is performance
- 1:48:23increasing,
- 1:48:25their performances are increasing by day
- 1:48:27by day.
- 1:48:30So, that's all for today.
- 1:48:32Do you have any questions?
- 1:48:36>> [clears throat]
- 1:48:39>> So, if no questions, we can finish the
- 1:48:41class.
About this transcript
This page contains the full transcript of W4 RISC V ISA II EN by Hasan Erdem Yantır, generated from the public captions YouTube serves with the video. The transcript has 14,512 words across 2,589 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.
What you can do with it
Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to translate the transcript into 100+ languages.
Free YouTube transcript tool
YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, translation to 100+ languages, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.