 In this video we're going to describe an example on how to perform the execution of a subroutine and the creation of an activation block in the AVR architecture. So we're going to assume that we are writing the equivalent in assembly code of the following high-level programming language line. Let's assume that in result variable we are going to store the result when we invoke function with parameters p1, p2 and p3. So let's assume we already have partially built the assembly program that is executing this. This would be the program. We have a few instructions and then at some point we need to create the activation block. The first thing we need to do is to realize that we have the result in three parameters. We are going to assume that both the result and the parameters are 8-bit numbers. So we need four locations in the stack. The first one to store the result and then three additional ones to access the parameter. Let's assume that r0 has any value. This is just to reserve a space for the result. And now we're going to assume that the parameters are in r16, 17 and 18. So these are respectively p3, p2 and p1. These four instructions then are the ones that are placing or reserving space for the routine to return the result and to access the parameters. After these four instructions we call the function. With the call instruction. We know that this will take the execution to the place where function has been defined. In other words, this first instruction over here. In this first instruction what we would do is create, if needed, a space in the stack for local variables. So we might need some additional push instructions just in case this function needs local variables. And we decide to store them on top of the stack. After that what we need to do for the activation block is to create a duplicate of the stack pointer in register Z. We're going to do that because register C is going to be used to access both the parameters and the result. Now how do we create a duplicate of the stack pointer? In AVR we achieve that with two in instructions. So we're going to say that in R31, which is the upper part of the Z register, we're going to bring the value of the input output port 3E. And in register R30, which is the lower part of register Z, we bring the input output port 3D. So this is basically copying the stack pointer to register Z. After that we're going to carry on with the instructions of the subroutine. And now the important observation is the following. We are going to assume that these local variables are not needed. We're not going to reserve any additional space there. We place the stack pointer, the copy of the stack pointer in register Z. What we have here is now the possibility to access the parameters and the result with the following instructions. LDD, let's say for example I want to load R18 with the parameter Z plus 3. That would be accessing P1. LDD R19, Z plus 4 would be accessing P2. LDD R20, Z plus 5. Accessing P3, that would be my way to access the parameters. Then I would do some additional instructions which will require some calculation. And eventually I would have to store my result. And the way I would store the result would be with instruction STD, Z plus 6. And let's assume the result is in register R21. R21 is the result. Finally, I am done with my calculation. I am done placing the result in the proper location. I need now to restore the initial stack pointer. And I do the opposite of these instructions. Rather than bringing in the value 3 and 3D, I'm going to bring them out. So out in 3E, I'm going to put R31, which is the opposite of what I did here. And out in 0x3D, I'm going to put register R30. And finally, I return. I go back to this instruction. And in this instruction, following the call, what I need to do is get off the stack these three parameters. I could achieve that by 3POP R0 instruction. POP R0 and POP R0. And finally, access the result with another POP instruction. Let's say POP R18. There is the result. And then I would keep making my computation. So I know this code is a little bit obscured, but it will become much more clear as soon as we explain it with an example. So let's draw here the initial state of the stack. We have the stack pointer pointing here. Let's call this stack A. And this stack, it's going to be the stack that we find right before we start executing all these instructions. Now, after executing these four instructions, the type of stack we're going to find is the following. We still have the initial value here. Now we have one, two, three, four slots. This is for the result, but it's empty. But this contains P3, P2 and P1 respectively. This is the stack pointer. So this is the stack we find right before executing the instruction call. So far, what we have done is place the space for the result and three more data, P1, P2 and P3, in this order in the stack. Now it's when the call takes place and we go to execute this block over here. So we have a different stack here. Now we have here the initial value, R, P3, P2, P1, P3, P2 and P1. Remember that R contains arbitrary content whereas P3, P2 and P1, they contain already the correct value of the parameters. But now, since we performed the call, what we're going to have at the top of the stack is the return address. This is the stack that is found. Let's call it C. Right here before reserving space for the local variables. Now, if we needed local variables in this execution, we would create another block on top of it. In this case, we're going to assume that we do not need that local block variable. And what we're going to do is describe the following stack, which would be, let's draw it again, initial position here at the bottom. We have the stack pointer here, by the way. Space for the result, parameter 3, parameter 2, parameter 1, return address. Remember that the result has an arbitrary value, P3, P2 and P1 have the correct parameter value. This is the return address. And here what we're doing is creating a duplicate of the stack pointer in register Z. What this means is that the addressing memory of this location not only is now stored in SP, but it's also stored in Z. Now, in the AVR architecture, this return address is actually 3 bytes. It changes from model to model, but we could assume that this is, in fact, 3 bytes. If this is 3 bytes, we can see that I need to add 3 to the address Z to point to here. So this is Z plus 3, because I have to jump these 3 values, not these 3 bytes. This is Z plus 4. This is Z plus 5. And this is Z plus 6. So this would be the stack at the point D over here, which would be exactly at this location in the code. So here we can see now where this displacement are coming from. 3, 4 and 5 are the bytes that I have to jump from this address to get access to P1, P2 and P3, respectively. Where do I get these numbers from? Well, I know that this, for the AVR activation block, the return address is typically 3 bytes. It changes from model to model, but we're going to assume that it's 3 bytes. Therefore, if I add 3 to this address, I will obtain the address of the first parameter. If I add 4, it will be the address of the second parameter. If I add 5, the third parameter, and Z plus 6 is the address of the result. This is also the reason why this instruction over here is doing precisely that, storing the result in R21 in the proper location in the activation block. Now, the remaining instructions, what we're going to do is precisely to undo all these steps. After executing these two instructions, I'm going to have exactly at this location the stack in position C, because I've removed already this duplicate C and restored it with the stack pointer. After returning from the subroutine going here, the return address is going to be removed from the top of the stack, and the stack B will also be present after the subroutine call. And finally, after getting rid of the 3 parameters and obtaining the result after this instruction, I'm going to have the stack in position A. So in this example, what we have seen is how the program that invokes a subroutine is responsible of building part of the activation block. Another part is placed by the call instruction. A final part then is taken care of by the subroutine. Then the subroutine can operate over these parameters and result with displacements that are known. Finally, place back the result in the proper location and do the copy of the stack pointer. Restore the previous value for the stack pointer. Return instruction removes the return address from top of the stack. We go back here. And finally, the program removes the data that put on top of the stack and access the result.