Let us remember, that instructions have implicit numbers, and, and here they are.
So, when I take this piece of code, and
I load it into the instruction memory, here's what happens.
First of all, whoever makes the translation,
has to operate this according to a certain contract.
You know, if you write the assembler for example, some things we're doing week 6.
We will tell you that the length which makes some assumptions, and
some conventions, and you have to write your assembler, or
to carry out the translation according to these to this construct.
So, first of all, notice that label declarations are not translated.
Now, we have two label declarations here, POSITIVE and END.
One is that just before line 8, and the other one is before line 10.
They are not translated, they are ignored, and
they generate no code, surprisingly enough.
'Kay. What about the references to the labels?
Well, the references to, to the labels definitely get translated,
and what used to be @POSITIVE becomes @8,
because 8 is the instruction just after POSITIVE.
And what used to be @n becomes @10 for the same reason.
So the second part of our contract is that each reference to a label is replaced with
a reference to the instruction number following that label's declaration.
So, once we keep this thing in mind, we can happily use invent and
use as many labels as we want in our program.
And then we can use these labels to effect the notion of branching.
Okay.
So having dealt with branching.
And obviously, it's something that we turn to,
because you cannot write non-trivial program without branching.
Let's move on and talk about another obstruction called variables.
All right. So what is a variable?
A variable is an obstruction
of a container that has a name and a value.
And in higher, high-level languages,
we have different types of data, different types of variables and
yet, in the lower level of machine language or at least in the,
in the lower level of the Hack machine language, we have only one variable type.
We have only 16-bit values to worry about.
And this obstruction can be delivered or
can be implemented by using a single register in our data memory.
So we use a single register to represent everyone of our variables,
if we want to create variables in our, in our program.
So here is an example in which variables come into play and
in this program I want to flip the values of RAM zero and RAM one.
And I do it using a classical programming idiom that
appears in practically every basic programming course.
I create the variable, typically we call it something like temp to denote
the fact that it's a temporary variable and I need it only for this purpose and
I do some manipulations that end up delivering the necessary flip operation.
So the question is how do you do it in in machine language?
Where so far, we didn't have a notion of variables.
So this is a good a good opportunity to, to introduce them.
Well, here is how I decided to do it.
And let us focus on the red instructions in this program.
And in particular in the first red instructions,
I declare a variable called temp and then I immediately go on to use it.
Now what is the meaning of this cryptic command @temp?
And notice that unlike labels and references,
we don't have a corresponding label called temp.
So what do we mean when we say @temp like this?
Well, here's what we mean.
Basically, we we present the following pledge to the computer.
Please go to the memory unit.
Find some available memory register.
Let us assume that it's register number n and
use it from now on to represent what I prefer to call the variable temp.
So from now on, whenever you see a symbolic instruction @temp,
I request that you treat it as if it were an @n
instruction that we already know how to handle.
Okay.
So this is the meaning or that's how I realized this variable obstruction.
So let us observe what happens when you translate this program and
load it into instruction memory.
Well the first observation is that when you look at the code,
you see that what used to be @temp became @16.
And because @temp appears twice in the program,
we have two occurrences of the @16 instruction.
So how does this happen?
Well whoever wrote the assembler or
implemented this translator worked according,
according to a contract that we as the language designers have put together.
So the contract has two rules as follows.
First of all, a reference to a symbol that has no corresponding
label declaration is treated a s a reference to a variable.
We assume that the programmer wanted to create a variable.
And the second rule is that variables are allocated to
the RAM from address 16 onward.
In this particular example, we have only one variable, so
it ends up being allocated to RAM 16.
If we'll have more variables in a program,
we'll use RAM location 17, 18 and so on and so forth.
And practically, we can use as, as many variables as you want.
And I can say it safely, because typically, programmer use only, you know,
half a dozen or a dozen variables something like this.
And in the Hack language you can actually use thousands of variables, but
no one actually comes up to this to so many variables.
So in closing of, of this little section about variable.
If you look at this piece of code you will realize that this
program is relatively easy to read and debug.
You know, we have a symbolic label and we have a symbolic variable @temp and
it's much easier to understand what is going on here compared to the program
that we wrote before when we used actual numbers to represent the addresses.
This program has another very nice virtue, which is more subtle and
this is the fact that this program is what is known as relocatable code.
I can take this program and load it into memory not necessarily to address zero.
I can put it anywhere I want in memory as long as I remember what is the base
address that they used for this program.
This is extremely important, because as you know, when you work with your personal
computer, you typically have several programs executing at the same time.
So you can imply from this that several programs are loaded into your main memory.
And once we write this program carefully using symbolic references,
we don't have to worry about where they will be located in memory.
We can write something called loader that takes care of this
o this technical detail.
So symbolic programs are good.
The next programing idiom that I would like to discuss is iteration.
So for example, suppose we want to compute the sum of the series,
1 plus 2 plus 3 all the way up to n, where n is given input.
How do we do it?
Well, normally, you use some accumulator,
a variable to accumulate the running total of the series.
So you set this variable to 0 and then you do 0 plus 1, [COUGH] gives you 1.
1 plus 2, gives you 3.
3 plus 3, gives you 6 and so on and so forth until you reach n.
Now, if you have to write this program in low-level language,
it always pays off to begin with some low-level oriented pseudocode and
this is what i did here.
So, once you convince yourself that this
Pseudo code actually delivers the required functionality.
We can move on and translate this
pseudo code on paper into symbolic machine language.
So, let us begin with the first part of of this of this
program in which we declare and
initialize the three variables n, i, and sum.
So first of all, notice that there's a one-to-one mapping between the name of
the, the variable that we use in my pseudo code to the name of variables in
the symbolic language, which is, which is kind of nice.
So we have these three variables and
let us assume that they translate only this part of the program and
load it into the instruction memory, here is what I'm going to get.
@n would be translated into @16.
At i into @17, and @sum into @18.
This should not be surprising because it follows
the contract that we discussed earlier.