 In this video, we're going to talk about four aspects to take into account when writing assembly programs, how to define data, how to handle labels, what do we have to observe when we are manipulating the stack, and how to manipulate the registers. So these are things that we need to take into account when we write our assembly programs. Let's talk first about data. So as we said, data is defined whenever the assembly program encounters a line saying dot section dot data. Now inside that section, you can use several directives to define different types of data. The first one we're going to study is dot byte. Let's assume that we proceed that with the label numbers followed by a column and then dot byte. Dot byte is a directive as you can imagine, allows us to define certain values for the different bytes that will be stored in memory. And you can define a series of values. Let's say, for example, first we define 38, then and we can combine different formats. We define another one, which is 0B1101100. Then we can define another one that is, for example, 0X3F, then another one surrounded by a single quote that is A, and finally another one, which is 0633. And as you can imagine, and we've seen before, this would be in decimal. This is definitely with the 0B prefix a binary number, 8 bits, therefore, if it's an byte. This prefix definitely denotes hexadecimal. This is ASCII encoding, so it will be the representation of A in ASCII. And finally, the prefix 0 denotes octal. So here we have this directive that allows us to define different types of values that will be placed one next to each other in memory. So the effect of this directive would be, if we could take a look at memory, this would be the consecutive bytes. So number 38 would be stored in this position, then the 0B in the next one, 0X3F here, A would be stored in this position, and this value would be stored in this one. So two things to take into account. One byte in size, each number, as the directive says here, and very important consecutive positions. Okay, what else can we define here? So the other directive we can use, let's use it with something we call message. We can use this directive, which is called .ASCII, which allows us to define a string surrounded by double quotes. A similar one is .ASCIZ, which allows us to define also another string always surrounded by double quotes, and a third directive, which is .String, followed by, again, surrounded by double quotes as string. Now what are the difference between these three? This one is the regular one. They just take the representation or the ASCII encoding of these characters of this string, and they are placed in consecutive positions in memory, and nothing is added. What do we mean by nothing is added? Well, because the following one, the one that is .ASCIZ, adds an extra byte at the end with value 0X00. So the difference between this directive and this one is that whenever we see this string here, we can count on being in memory, the encoding all these letters plus 0X00, which is added at the end. Whereas in here, nothing is added at the end. The only thing that is encoded is the string as you see it here with the characters that you see it here. And the third directive, .String, is very easy because it's nothing more than a synonym for the previous one. So these two are the same. All right, so we know how to define numbers and how to define strings. The third directive that we're going to use is .Space. Now .Space allows us to define simply a chunk of memory in which we are going to store something. But we don't need to provide neither a byte nor an ASCII. Typically, the way we define it is with two numbers, A and B, separated by a comma. And this defines A consecutive bytes with value B. So for example, .Space 3 comma 2 will define three bytes with the value 2 as the initial value. Or if we don't specify B, then it's taken as the value 0. So these are the three directives that we can use by this group of directives to specify strings or .Space to specify empty space. Let's now talk about labels. These are very important in assembly programs. I've written three labels here as a prefix for these three types of directives. Now remember, labels are optional. You do not necessarily need to write a label next to each of these directives. However, labels are used for two purposes. The first one, perhaps the most intuitive, is to refer to the data. So in here, as you can see, the label numbers is in a position. That would be this one here, which points to the value 38. The definition of the labels allows us then to do things like this. I would like to load, and I use the instruction LDS, in register R12, whatever points to in the label numbers. So what this thing means is that the number 38 is loaded in R12. So this is the first interpretation. When I put the label in an instruction LDS, I'm referring to the data stored in this position in memory. And this position in memory, the content of it, goes and is loaded in R12. I can use also the instruction STS and say STS numbers comma R12. And this is the opposite. Content of R12 is stored in memory. OK, but, and here comes the tricky part. Labels have a second interpretation. Sometimes we want to refer to the element in which they are placed. But some other times, what we want to do, we want to refer to their address. In other words, numbers refers to this position over here. But rather than getting number 38, I would like to get the address that this label is placed or corresponds to. And the way to do that in the AVR architecture, we need two instructions, which work like this. Suppose that I do LDI R28. So LDI stands for load and immediate. I'm going to load a constant. And the syntax careful with this is L08 numbers. And then another instruction, LDI R29 HI8 numbers. Now these two instructions are typically together for the following reason. First, the address has 16 bits. So how do I access to those 16 bits? Well, these two functions, LO8 parenthesis and HI8 HI8, sorry, parenthesis, are assembler directives. What it means is that these two expressions are replaced respectively by the eight bits, least significant eight bits of the address in which numbers is placed. And the eight most significant bits of this address. So as a result, the address is now placed in the register R29 column R28, which is our way of saying that we concatenate those two registers, each one eight bits, to refer to a 16-bit value. So these are two very different interpretations and very important of the label. So remember, label can refer to the data they point to. Or we can also get a hold of the address of that label. And we get a hold of that using these two directives, LO8 and HI8. Let's talk now briefly about the stack. So we talked about data. We talked about labels. Now we're going to talk about the stack. Now the stack in this architecture needs to be manipulated in using basically two rules. The first one is that it's used for temporary values. In other words, you shouldn't think of the stack as something that some portion of memory that you're going to leave a lot of data there for any purpose. It's just for temporary values. So you upload or you load data in the stack with the push operation. And then later, you remove that data with the pop operation. Remember to instructions, push, and pop. But perhaps the most important rule with the stack is that your code has to start and finish with the same stack. Now this is extremely important. I repeat, extremely important. Because if you don't do that, then your programs will not execute correctly. What this means precisely is that whenever you start the execution of a program, you have to assume that the stack is in certain position. You still can use it for temporary values. But you have to remove any other value that you have pushed to the stack, such that you comply with this requirement at the end, the start and finish of your program, observe or find exactly the same stack. And finally, after talking about data, labels, and stack, let's talk about registers. How do I handle registers in my assembly programs? So there are basically four rules that we need to observe. And these rules derive from the architecture. They are arbitrary, and they need to be observed. Register R0 is free to use. No restrictions on that one. You can do whatever you want with that. Register R1, on the other hand, must be 1 at all times. Sorry, must be 0 at all times. So you can change the value of that register. You always have to observe that it has to be 0. Registers R2, all the way up to R17 and then R28 and R29. Actually, these registers, be careful, because you have to save them at the beginning of your code and restore them at the end of your code. What does this mean? It means that if you plan to use any of the registers in your program, the first instruction that you have to place in your program are those instructions to push to the stack the value of these registers. Such that before finishing your program, you restore them and make sure that they have exactly the same value they had before your program started. So this translates into push and pop instructions. So remember, and this is again one of the most common reasons why assembly programs don't work, because you don't observe this rule. You have to make sure that before your program terminates, these registers have exactly the same values they had when it started. And for that, you use the stack, remembering that you have to restore exactly the same stack at the end. And finally, the other rule is that registers R18 through R27 and then registers R30 and R31 are for you to use freely. But in other words, you can do whatever you want with these registers. You don't need to observe these save and restore rules as we stated before. But you may lose their value if a call is made. So another way of looking at these four rules. R0, you can do whatever you want. No need to save or restore it. R1, you just leave it alone and set it to 0. These registers, you have to make sure that you make a copy of them in the stack and then restore the value before you finish. And these are the registers you can do whatever you want, except that if in the middle of your call you make a call to a subroutine, it might happen that these registers get overwritten. In other words, any value that you would leave in any of these registers is not guaranteed to be there by the time the call to the subroutine is finished. So again, these are rules that you have to observe. Make sure you observe them in order for your assembly programs to work in the AVR architecture.