📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

But How Does a Computer Actually Work? (from scratch, no prior knowledge needed)

Milen Patel11:54:41

Transcription

So, in this video, I'd like to try and explain just exactly how a computer works. And I know that sounds like an incredibly open-ended and difficult question to answer. And I'm going to go ahead and guess that the length of this video will make that self-evident that it's not any trivial question in itself.

But, uh, this is something that I wondered a lot growing up. And, uh, even when I got to college, I knew I was going to study computer science. But it wasn't until halfway through my degree where I took the course which answered this question and I found everything I learned really interesting. Ended up TAing that course for a few semesters afterwards and uh find the really low-level stuff of computing to be fascinating.

And I've been surprised at uh a the lack of direct resources online that can answer this question for just an average person who's curious and b how many uh friends I have working technical jobs or who studied computer science or related degree in college and are not too sure how a computer actually works. And I think um there's a lot of benefits to be held from this knowledge.

Uh if you are just curious like I am, I want to cater this video to be completely digestible even if you have no mathematical or technical background. And I also want this video to be useful for someone who might already be uh doing an engineering relating job because uh a lot of these lower level principles might actually affect how you structure code or just uh lay out your programs at a higher level.

Um so in this video I'd like to start with no assumption of what a computer work how a computer works. uh just basic mathematics will be assumed which I'm assuming if you clicked on this video you have a somewhat of an understanding of um we're just going to be starting simple with like addition, subtraction, multiplication, division uh and like exponents. I think that's probably all the background you need to be able to follow along for this entire video.

So I'm going to answer this question by making a CPU from scratch. Um and then we're going to go ahead take that processor uh which can run one program and build an operating system or just explain kind of at a higher level how an operating system can be built for our processor uh and what an operating system actually is because that's also a great question in itself.

Um but without getting into too much detail now the computer you're watching this on even if it's a phone uh is is doing multiple things at once. And if you're like me, uh you probably have this YouTube video open, iMessage in your background, um and maybe a few other tabs behind those two. And uh it's a really interesting question cuz we're going to get to a point in this video where you design a CPU and it can execute one program. And a really common and good follow-up question is how can my computer run multiple programs at the same time?

Um, and so we're going to go ahead and dive into what that looks like as well because it's a it's interesting to know how a computer works. Um, but I also want to make it pragmatic and get to something more modern uh, which is an operating system.

So, uh, I also would like this video to be useful um, even if you don't watch it all the way through. I have no idea how long this is going to be. I am guessing it will not be short though. And what I would hope is um for those of you who don't watch it all the way through, which is the vast majority, I'm assuming, uh the individual segments uh will be of value themselves. And maybe hopefully you learn something interesting along the way. Even if you didn't take it all the way, you learned something.

Um and what we're actually going to start at is one of the most interesting topics I think personally uh that anyone can know. And if you only watch this first segment of the video and nothing else, you've at least learned something really interesting.

Um, so I'm going to start by uh explaining how computers represent numbers and letters. Uh, how do we how can computers count? How can they add numbers? Um, and you've probably heard of something along the lines of computers speak in zeros and ones. And uh, this isn't nonsense. It's actually very true. Computers don't really recognize or process numbers the way we do. They only operate on zeros and ones. And once we uh understand how computers represent numbers, it's going to make sense why they do it like this.

Um without getting into too much specifics now, but also without being incredibly vague, uh I'll say when we design computers, um they're built with electricity. And so we can represent the absence of electricity with a zero and the presence of electricity with a one. Um and with this it it kind of gives us a lot of flexibility to well if we can represent anything in zeros and ones and we know how to represent zeros and ones with electricity or the absence of it. Then we can kind of build on top of that and design an entire computer.

Um, and you may be wondering, well, why don't we just use a little a little bit of electricity represents uh a one, a little bit more than that represents a two, and so on and so on until the the maximum of electricity we could have represents a 10, and then computers could just work with the the numbers we know.

Um, but from an engineering perspective, it's not that easy to implement. Um, I don't want to get into the specifics of electricity because that's also uh probably a little too low level for what I want to accomplish in this video, but um, it turns out electricity is is very inconsistent in in in I guess flickers might be a better word for what I'm trying to say.

Um, so we find it easier just to say have a certain threshold of of electricity, quote unquote, and anything below that we interpret as a zero, and anything above that threshold we interpret as a one.

Um, and again, it's not going to make perfect sense what I'm saying. If you're already a little bit confused, it should be confusing cuz I'm kind of jumping jumping ahead of myself here. So, I just wanted to give some context for why we uh represent numbers with just zeros and ones in computers.

So, let's go ahead and understand how computers represent numbers. Um, so I'm going to clear this screen here that you've been staring at for 5 minutes now. And let's start with uh a quick recap of how we represent numbers. So if I put the number 724 on the screen, intuitively you know exactly what this is. I mean it's a number you can rationalize. You can imagine say 724 uh pencils in your hand or something like that. But how do we actually uh how did we learn this? When you were in elementary school and learning how to count, this number wasn't always easy to you. In fact, the first time you saw this, it probably made no sense to you, but you're older now, you're smarter, and you know how to interpret this.

Um, so I'm going to redumb this back down to our elementary school level and uh see how we can build this number by looking at each of the digit positions. So, we know this right here is the ones place. That's probably not surprising. Um, we know this is called the 10's place. And then we know this is called the hundred's place. And uh this is something you know and you don't remember when you learned it, but you know that you learned it at some point. And we know that if we keep going, we have the thousand's place and then the 10,000's place, then the hundred thousand's place and the million's place, the 10 million's place, the 100 million's place, and so on and so on.

Um and so what exactly do each of these places mean? And how can we take the values from each of these places and and generate a composite number? Um, so it turns out that to to get the value of a number, uh, we have to, and this is going to sound painfully obvious and almost a little bit confusing because of how obvious and true it is to you, but I'm saying it cuz it's going to make sense when we look at the computer version. um to get the value of a number, we could look at the value of each of the digits places and kind of sum them all up together.

So, we know in the ones place, this four uh is just going to be whatever value is in that digit spot times the weight of that spot. So, right here we have 4 * 1, which equals 4. And then over here, we have a two and it's in the 10's place. So that's going to be time 10 and that's going to be 20. And then over here we have a [snorts] seven in the hundred's place. So we multiply it by the weight of that place which is a 100 and we have 700. And then we can as I said we could add all these values together. So once we compute the weight of each digit position we can go ahead and add those uh those scaled weights together. So then we have 700 + 20 + 4. And I'm going to stack those numbers on top of each other because that's kind of how we learn how to add numbers. Um, oops, not 24. Uh, and we know exactly that there's only one non-zero digit in each position. So it's just going to carry right down. Um, and so we kind of started with 724 and ended with 724. Um, and that's that's nothing too crazy.

Um, but let's go ahead and and structure that out a little more. So, what we saw here is that 724 is equal to 7 * 100 + 2 * 10 + 4 * 1. And where did that come from? Just to recap, it is for each digit position, we take the value that is in that that spot and then multiply it by the weight of the position. So we know the very first digit position is the one's place, so its weight is one. Then the next one is the 10's place, so its weight is 10. And then the next one's the hundred's place, so its weight is 100.

Um, and then if we were to expand, so we've kind of taken our number 724 and written written it out in this expanded way. Um, and hopefully I've convinced you that this is true and correct, and it it is. Um, unless I've made some error, but let's look at an even uh more alternative way uh to to to write out this expanded form. And all I'm really going to do is uh replace the weights um of the position. So, let me write this out and then we'll kind of uh revisit what I'm trying to say.

Okay, so I told you um that this is going to run on basic math. Uh and the exponent is probably as complicated as we need to get for you to understand everything about how a computer works. Um everything loosely put everything uh that I'm going to teach you in this video.

Um so just to recall that uh 10 uh to the 1 is is 10 10^ squared uh when we have a a number raised to an exponent it just means we multiply the number by itself that many times. Um so 10 by 10 is equal to 100. And then if we had 10 cubed we multiply 10 by itself three times. um and that's going to be a thousand. And then uh one caveat to that is um there's this rule that says anything raised to the zero power is equal one. Um and uh so that means that when we have 10^ the 0, it's going to equal one. Um, that's just something you probably learned in algebra 2, uh, from high school, which is probably so far out of your memory at this point, but just just take it to be the truth that, uh, anything raised to the power of zero, we're just going to say equals 1.

Um so what I've done here is I've rewritten our expression uh in this kind of exponentiated form where each component in our sum is some number multiplied by 10 raised to some power. Um and we also have it that uh the powers are increasing. So we start with the zero power then we go to power one and then we go to power two. Uh, and that that's funny enough and that that's actually uh not surprising or the more you think about it, the more unsurprising it should be because uh 10^ the 0 is 1 and so that's the one's place and then uh 10 to the^ of 1 is 10 and that's the 10's place and then 10 to the^ of two is 100 and that's what we call the hundred's place.

Um so all we've really done here is is taken our number 724 and in write it out in this expanded form. Um and that is all we will recap about the numbers that you and I know. So now that we know uh or now that I've shown you just an alternate way to consider the numbers we know um we have the context uh to go ahead and move on and learn how computers count numbers.

So this is how we count numbers. And it turns out computers do it very similarly. So all of this right here is called decimal. That is our human way of counting numbers. And it's also something that's called base 10. And what does that mean? Base 10 is worth uh worth probably discussing a little bit before I move on and and jump to the computer equivalent. But um one way to interpret base 10 is that it means that for any digit position in a number, there are 10 different values that could go into that digit spot. So uh in our 724, um let's say I pick this digit position right here. We could either have uh a zero, a one, a two, or all the way up to a nine. Um so we could have 10 different numbers could go in this spot. And if you're wondering why it's not nine, it's because uh one through nine is nine numbers and then the digit zero lets us add one and so we have 10. So we actually have it that in uh any digit position um there can be 10 different values in base 10.

And uh let's also see what happens when we're counting. So for counting in base 10 i.e. The only way that you and I know how to count for now, um, we start with the number zero, it becomes one, and then two, three, and then we're going to go all the way up and we get to nine. And each time here, we're just adding one. So, we're just plus one, plus one, um, all the way down. We get to eight, we add + one, we get to nine. Um, and we've used all 10 available values that can fit in this digit position. So when we want to add one to nine um we're stuck. We can't do that in one digit position. So we have this idea of rolling over um where we we reset this digit back to zero and then carry carry uh a one over to the next digit place.

Um and so if we take these numbers and and write it out in our expanded form, then we know 9 is just equal to or let's start with 10. 10 is equal to 1 * 10 uh + 0 * 1. Um oops. And then if we have 9 um then we have zero in the 10's position and a nine in the ones position. Um, and so it's kind of curious that when we we get to the maximum value in a current digit position and we want to add one to that, then we roll over the current digit position back to a zero and then add one to the next digit position to the left. This kind of makes sense because what we're doing here is we are when we have this nine here, um, we know that we want to add one more to our collective value. So what we could do is subtract nine from this spot and then add one from this spot and that gets us the exact difference. Um that that is the same as accomplishing uh a net just addition of one. We took all the value from the uh the digit position to the right and then reset it to a zero and then added one to the next digit position to the left and this is the same number.

Um, so that's how we kind of carry over and and we kind of see this happen when we add numbers. So if I go to a quick example where we add numbers, let's say we have um 18, we want to add three. Then uh we have 18 + 18 + 3. We start in the rightmost digit position and we add the two numbers together. So an 8 + 3 is an 11. And you remember from elementary school that you put the one down here, the remainder, and then you add the carryover up here. And um then you do 1 plus one is two. And that's that is the uh kind of exact same logic that we're showing in this in this uh extended form. But obviously when you were younger, there was no no reasonable way for you to understand this version of things. You kind of just learn this rule that you uh you kind of take what you have. if if you if a digit position exceeds 10, you put the remainder down below and then add one to the carryover.

Um, and so that is uh just some more context that we're going to see this come back very shortly. So we saw that base 10 is this idea that we can have 10 different values in any digit position. And now we're going to come and uh learn what base 2 is. So we said humans speak in base 10. Um so this decimal is synonymous with base 10. And now I'm going to make this claim that computers uh operate in base 2. And this is called binary. And so what does this actually mean?

Um well we said in base 10 what that means is that in any digit position you can have 10 different values. And so what we can translate that to in base 2 is then in any digit position we can have two different values. And those two different values are zero and one. Um and that is just exactly where the idea that computers only speak in zero and one come from.

Um, but let's go ahead and see what that means. So, um, I'm going to give us a binary number. So, we're going to start with the binary number 1011. Um, and this is a binary number. This is this is not to be confused with the number 1,111. This is uh which is in base 10. Um, so I will distinguish it by subsetting it with this two. Um, so I will try to make the distinction as clear as possible. If we are speaking about a decimal number, i.e. a number that you and I are familiar with, um, I'll write a 10 next to it. So, if instead I wanted to say, I guess our example above, we had the number 724. So, from now on, I would say 724 base 10 just so you uh don't get confused. But in general, it's for I'm not going to try to give you a a complicated example. Um, so if there's just zeros and ones, it's probably safe for you to assume that I'm talking about base 2. And if there's other digits, then it's the base 10 that we're so familiar with.

Um, and let's go ahead and I'm also going to rewrite our expanded form of 724. So, let me move this down. Um, and for 724, we said it was 7 * 10^ 2 + 2 * 10 1st power + 4 * 10 0 power. because we start uh with the lowest power of 10 and then we just keep adding one each time.

Um, and so now we're I'm I'm kind of we're kind of curious here. Uh, how can we take this binary value and translate it back to a decimal value? What does 1011 mean in binary? Like what number is that to us? Um, and it turns out we're just going to follow the same exact expansion rules. So, uh, we're going to sum up for each digit position, um, the value in that position, which is either a one or a zero. And then instead of 10 raised to some power, we're going to use two raised to some power because this was for base 10, but now we're going to be using base 2. So it'll be we're going to start with um the one spot is going to be two to the zero and then instead of the 10 spot being afterwards uh we're going to have the two spot which is a little interesting cuz you know in our in our current uh number we would have um in our in our binary system that we're so comfortable with we start with the ones position and then go to the 10's position and then the hundred's position.

Um, and now we're going to start with the one's position and then go to the two's position cuz that's 2 to the first power. And then after that position, we have two to the second power, which is four. Um, and after that would be 8. And so if I come to our original decimal example, we notice that between each of these, we're multiplying by 10. And now we're in each of these, we're multiplying by two. Um, we're looking at increasing powers of two, which is is is pretty interesting.

Um, so let me go ahead and erase that. And if this is feeling a little bit confusing, I really hope it it it should it shouldn't feel intuitive yet. Um, I've said a lot of random things so far in this video. Um, and now is where we're actually start tying them together. So, let me spill the answer for you on this one, and then we'll we'll walk through and see what it means.

So, um, let's start with the rightmost digit position. Uh, cuz we start with, uh, 2 to the^ of 0. Um, so I'm going to do 2 to the^ 0. And what do we multiply it by? We multiply it by the one that's there. And then we have that digit position done. Now we come on to this digit position. Uh, we have uh, we're not on the 2 to the^ of zero. Now we're on 2 to the^ of one. And then we multiply that by whatever is in that digit position, which also just happens to be a one. Um, let me move this over here. Um, and then we then move on to this digit position, which is the 2 to the^ of two position. And what's there is multiplied by a zero. And then we come on to the very last digit position. And that one is uh the next power to use. We use powers 0, one, and two. So now we use the power of three um and we multiply it by whatever is there. So now we have this expression um and you might need to pause here and just read this out loud to yourself to make sure that you understand exactly how I derived this long form expression. Uh it may not be clear what exactly I'm doing but how I got this expression should be clear.

Um, and you should also be able to understand that uh in base 10 i.e. top row binary that or decimal sorry that we're used to. Uh each digit position is some increasing power of 10. That's the weight for each digit position. Now that we're in base 2, each digit position, the weight of that position is some power of two. Um, and let's go ahead now. Uh, if you need to pause and and just run through what I explained, do that now. But let's go ahead and uh expand this out.

Um, so we know that uh we have 1 and then 2 to the^ of 3. So 2 cubed is 2 * 2 * 2 and 2 * 2 is 4. So * 2 is 8. So we have 1 * 8. And then we have 2 ^ 2 um which is 2 * 2 which is just equal to 4. And we multiply that by 0. Um, and then we have 2 to the 1st power which is the easy one. And we all know that's just two. Any number to the first power is just saying multiply that number by by itself uh once not two not two times that's squared. So we just have it once then it's just that number itself. Um, and then we also said earlier that anything to the power of zero is just one. So now we have this expression and now we're this should look pretty comfortable. Uh no exponents here. So 8 * 1 is 8. Uh 0 * 4 is 0. 2 * 1 is 2. And 1 * 1 is 1. And that's just 8 + 2 which is 10 + 1 which is 11. So and that's base that's uh base 10 11. So the the number the 11 we're comfortable with. So now I can tell you that this number 1011 in binary is just 11.

Um, and that is a totally different way of representing a number uh that we are already familiar with. Um, and this is really interesting because we only had zeros and ones to work with, but we were able to map that back to a number that we know perfectly. Uh that doesn't need to just use zeros and ones.

Um, so let's go ahead and look at uh one more conversion example. Um, and uh let's do the number um 1001. Um, and kind of go through the same process again. So uh we know that the weighted positions let's start with that actually. Um, let me make this a little bit wider so we can write on top of them. 1001 that's base 2. And we want to know what this equals in base 10. Um, and so if we start from the right we know that this is the 2 to the 0 position then this is 2 to the 1 then this is 2^2 and this is 2^3. Um, and that's just for our reference. Um, so we can go ahead and generate this uh this long form expression where we know if we start from the very right we know that that is 1 * 2^0 and then we have a 0 * 2^1. Um, and the the zero comes from the fact that that's what's in this digit position and that's also where the one comes from here. And then for the next digit position we have a 0 * 2^2. And then for the very last digit position we have 1 * 2^3.

Um, so then we can go ahead and combine those. We add those all up. Um, so this 1001 in base 2 is equal to 1 * 2^3 + 0 * 2^2 + 0 * 2^1 + 1 * 2^0. Um, and this time, uh, I could expand this all out, but there's something interesting to note here, and that's that we have two examples of us multiplying a number by zero. And from basic numbers, uh, as you also learn in school, anything times 0 is just zero. Um, so there's no point in us doing these expansions of converting 2^2 to 4 uh, just to multiply by zero. If we see that it's being multiplied by a zero, let's just ignore it because we know it's not going to add any any values to our final sum. And that's that that that's going to save us some time later. Uh, if I gave you a super long binary number that was like say a 100 digits wide and told you to convert it um then you know this would this would be kind of uh a big time saving um for all those zeros that you could drop out.

Uh, so then we can simplify this expression. Uh, we dropped out those zeros. We just have these two terms left. And then we know that 2^3 is 8. So that's 1 * 8. And then uh remember that anything to the power of 0 is just 1. So then we have 8 + 1 which is 9. So and that's 9 in the decimal we know. So this 1001 in base 2 is equal to 9 in the number system that we know. And this is uh really cool. Um, I remember when I first learned this, I was kind of mind blown uh at the fact that we could take these random se this seemingly random sequence of zeros and ones and then map it back to a number that we are so familiar with.

Um, and that uh should make it clear how we go from binary the zeros and ones to decimal which is a number system we speak. Let's look at one other example. What if I gave you this this big number right here in binary? That's not the number 10,000. That is 1000 in binary. But I would like to know what is this in base 10. Um, and uh well, we know let's just go ahead and count our positions and then generate this expression. Um, so we know our digit positions start at 0 1 2 3 and four. So we have uh that it equals 1 * 2^4 and then + 0 * 2^3 + 0 * 2^2 + 0 * 2^1 + 0 * 2^0. And from the rule we learned in the example before, whenever we're multiplying something by zero, we can just get rid of that term cuz it's going to equal zero. That's exactly what's happening in all of this expression except for this one digit position. And then we just know that uh 2^4 is equal to 2 * 2 * 2 * 2. And that's going to be uh 2 * 2 is 4. Multiply by 2 again you get 8. And then one more time you get 16. So this number right here uh 1000 in decimal is actually going to be equal to 16 or sorry 1000 in binary is going to be equal to 16 in decimal.

Um, and uh luckily this is a very popular concept. So if you're feeling a little confused here um on anything I've shown that's totally fine. Just go ahead and Google it. watch another YouTube video if you need to. Um, I do not want to do more examples just because this video could drag on forever.

Okay, so now we have learned up to this point how to take a binary number and translate it back into the base 10, i.e. decimal number that we're more familiar with. So, what I'd like to do now is the exact opposite process. If I have a number like 14, how can I get it to binary? And we're going to almost take the inverse of the exact process we we had before. And why are we going to learn this? It's going to be because um we're going to want to program our computer eventually. And we're going to want to be able to store numbers in our computer. And it's going to be useful then, in fact imperative that we know how to take the number we want to put into our computer and convert it to binary so we can load it into the language that the computer speaks.

So uh we've been working with this number 724. So let me go ahead and give us the expanded version one more time. So we said this was 7 * 10^ of 2 + 2 * 10 1st power + 4 * 10th power. [snorts] And I'm also going to go ahead and bring up this binary example from above. Uh where we had let's just say 1011. And I'm going to subscript this with two because it's binary. And we said this is equal to 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + uh sorry 1 * 2^0. [snorts] And if we notice something here um everything on our right hand side is decimal numbers the ones we're very familiar with. And we know that we take this this left-hand side which is unfamiliar to us and we're able to expand it out in a form that is actually only containing decimal numbers. [snorts] And this is the exact kind of logic we're going to take to get a number from binary to decimal. So if I have the number 724 and want to convert it to to binary then if there's a way where I could write it out in this expanded form as uh numbers zeros and 1* 2 to some power then we know we can just read the the multiplicative coefficients left to right to know our number. Um in this case it's easy. we have we have a one and then a zero and a one and a one and this is exactly how we end up with this number over here.

So this is a little abstract um and this is probably a little more complicated than what we just learned. It's my personal opinion that taking a a binary number and converting it to decimal is easier than me asking you to take a decimal number and convert it to binary. But let's go ahead and do this by working through an example.

Um, so let's take the number 15. 15 in base 10 i.e. just the regular 15 we're familiar with. What exactly is that in decimal or in binary? Um, so question mark base 2. What we want to end up with is some expression where we start with 2^0 and work up to some power of two and multiply each of those terms by either a zero or a one. uh until we have some equivalent value that sums up to 15. And as we kind of saw earlier with this binary conversion, we only really need to care about the powers of two that are multiplied by one. I in our example here, this one uh since it's multiplied by zero, it drops out. So we kind of know that uh I'm going to move this out the way. Uh this is really just equal to uh 2^3 + 2^1 + 2^0.

Um, and I'm gonna make this interesting claim uh that any number in decimal any number that you can think of can be expressed as a sum like this. And what do I mean this? I mean a sum of powers of two. And there is a exactly one way to represent each number accordingly. Um, and I can show you some examples. So if we have the number one in decimal, then we know that two to the 0 is just one. And then let's say we have the number two in decimal. Well, this is easy as well. We know 2^1 is just two. Uh, but let's look at let's look at what happens when we have three. Um, well, we know how to represent one and two in binary. Uh, and we can just add those together because they sum to three. So we would just add their binary representations together and we'd be left with 2^1 + 2^0. And then four is easy uh because we would know that 2^2 is 4.

Um, and then we'll do one more which is five uh and we know that uh 5 is equal to 4 + 1. So that's 2^2 + 2^0. And now uh for each of these let's uh go ahead and convert it back to binary. Um, so let's start with this this five because I think it's the most interesting case. And we know that the uh we can't skip any digit positions. I.e. the rightmost digit position in our binary number has to start at 2^0. The power has to be zero. And then we have to keep working up from there until we we have all the powers that we need in our sum. And that's the same way when you're when you're building out a number in decimal. You can't skip the 10's place or the hundreds place just because the value in that digit position is zero. You have to explicitly write a zero to make it apparent that there is no value in the 10's place and then the next value is the hundred's place. So in our example here what we would need to do is um I'm going to bring out in this long form. So we we know we have this 2^2. We don't have any uh thing multiplied by 2^1. So we do is we just leave it as a zero. We make the coefficient zero because that means it multiplies out to nothing. And then we have 1 * 2^0. And this is the exact form from earlier where it was pretty easy from there just to read the coefficients left to right. 101. And now we have our decimal or our binary number. Sorry. So we took our five and uh got it to a binary representation. And if you don't believe me, well, the evidence is on the screen. But if you want to verify for yourself, pose the counter question. What is the decimal representation of the value of the binary value 101? And if you expand it out like I've already done, you're just going to get five.

And uh let's do this for the example of 42. So we have all we have is 2^2. But we know we have to get all the way back down to the power of zero. 2^0. we just add in 0 * each of those terms. So we have 1 * 2^2 and then we don't want to add anything else. So we just do 0 for the first power of two and zero for the zeroth power of two. And then we know we just read these coefficients left to right which is 100. So that's how we represent four in binary. And in our example here, we have it easy cuz we have every power of two uh in the entire range included. So we know that's 1 * 2^1 + 1 * 2^0. And that's just going to be equal to 11 in binary. And we'll just go ahead and finish out what we have here. Uh, we know that 2^1 is equal to 1 * 2^1. Then we don't want to add anything else. We just multiply the remaining terms by zero. And there's only one remaining term for us to get back to the power of zero. So, we're just left with 10. Uh, and that's supposed to be subscripted with the two. And last but not least, uh, this one's trivial. Um, we've already worked our way back down to 2^0. So, we just have that one term and that's just equal to one.

Um, so hopefully you notice a little bit of a pattern here. uh where I have been able to convince you at least that the first five numbers in decimal are are uh able to be expressed as a sum of twos raised to various powers. And if we can figure out for any number what that sum is, then I've shown you it's pretty easy once you have that to expand it out and then get the binary representation. [snorts] So let's try a uh a little bit more difficult example. Um, uh let's try 13. And >> what we're going to do is we want to find the sums of twos to various powers that sum up to 13. And we're going to do this by starting uh with the biggest power of two that is that can uh contribute to our sum. So uh I'll go ahead and and write this table out over here. We know 2^0 is one. 2^1 is two. Then 2^2 is 4. 2 cubed is 8. 2^4 is 16. 2^5 is 32. And I'll do one more. 2^6 is equal to 64. And what we want to do is just start with the biggest uh x such that 2^x is less than our target value of 13. And that's going to happen uh right here. 2^3 is 8 which is the largest value uh that is less than or equal to our target value. So we know that uh 2 cubed is going to be in this expression and then when we have uh we kind of have um 13 on this side and we have eight on this side and so that means we need to get five with some remaining combinations of entries on this list. So we'll do the same process for five. And if we look at this list, uh we know that one is less than five, 2 is less than five, four is less than five, 8 is not less than five. So this two 2^2 is the biggest power of two, which is less than or equal to our remainder, which is five. Our remaining sum, should I say. So then I'll add our two squared in. And now we have a four. And so we know that 13, we have 13 on this left side and we need to get 13 on the right hand side or else they're not equal. And we have 12 on the right hand side. So we just need to get one more. And that's easy enough because we know that 2^0 is one. So I'll just add that in. And now we've uh done the exact task that we we we said was the difficult part, which is expressing our target number of 13 as a sum of various powers of two. So now let's go ahead and uh I should have demarcated this with a base 10. So you know I'm working with the decimal number. Let's go ahead and and bring this out to the expanded form where we add in the ones and zeros and the missing powers of two. So we would know we have 1 * 2^3 + 1 * 2^2. We don't have any term with 2^1. So we multiply it by zero. So it doesn't actually add anything. And then lastly we do have 2^0. So we will put a one there. And from there, it's pretty easy. We just read left to right what the coefficients are. And we have uh our binary equivalent. So 13, the decimal version of 13, the number that you and I know is 13 is equal to 1101 in binary. And you can expand this out, which is kind of what we have right here to prove that in fact uh I am not lying to you. It is 13.

So let's try one more example of that just because I think it's a little complicated. Um, let's go ahead and do uh let's say 22. I just picked it off the top of my head. Hopefully it works out to be somewhat pretty. Um, so we have to find the uh the sums of powers of two again. And I'm going to go a little bit faster this time. So I'm just going to look at our list and I can see that 16 is the biggest value here that is is less than or equal to 22. So I know we have a two to the four here and let's keep things easy. So, I have 22 = 16 + uh we know we're going to need something else cuz the left hand side does not equal the right hand side. And 22 - 16 is 6. So, we're trying to get a six now. Um, and four is the next candidate here in terms of largest power of two that doesn't exceed our target of six. So, I'll add a two squared into our sum and that's going to be equal to four. And now we have 22 on the left hand side and 20 on the right hand side. So all we need is to get two uh to our expression. And that's easy. We know 2^1 is just two. And now we know that the 22 is equal to 22. So we've we've con we can convince ourselves that this uh left-hand expression here is equal to the right hand side of the expression. And so then what we can do is we can go ahead and write this out in the expanded form which you should be comfortable with now hopefully or it should at least be becoming apparent to you. And that's equal to 1 * 2^4. There's no 2^3. So we just write a zero as the coefficient because it multiplies away. Uh and that's because anything multiplied by zero is just zero. So this this term we just added contributes nothing to our sum. And then we have a 2^2. So we'll add the 2^2 in. And we have a 2^1. And we do not have a 2^0. But we need to go all the way down from the largest power of two, which is four, all the way down to zero. So we stop like this. And then we

Can we can take these coefficients and just read them left to right. So that's 1 0 1 1 0. And that means that 22 in decimal is equal to the binary number 1 0 1 1 0. Cool.

So, you've now uh gotten a pretty high level but also complete understanding of what binary is. I've shown you how to take a binary number, convert it to decimal so you can make sense of it and also how to take a decimal number and convert it to binary. And there is one final thing that we will want to do and be able to understand about binary numbers and that is how do we add them?

And I talked a little bit about this earlier when we we talked about decimal, but let's go ahead and and recall our decimal example. Let's say I have 74 + 39. Well, we keep we start at the rightmost digit position and we keep adding the values in the corresponding digit position. So, we'd add this 49 together and we'd write the sum of them below. So, let me actually pick a better example. Uh, let's do uh 782 plus um 531. So in our example, we'd start with this rightmost digit position. And we just know 2+ 1 is 3. So we write it down here. And we move on to the next digit position, which is 8 + 3. And 8 + 3 is 11. Which you should remember this means we have carryover. So we put the remainder, which is 1, down here. And then we carry over a one up here. And then now when we get to the next digit position, we add 7 + 5 which is 12. But we also have to factor in this carryover which makes it 13. And that's exactly what we do.

So for decimal, what we did is we started at the rightmost digit position and for each digit position, we added the corresponding numbers for A and B. If I'm letting this be A and this be B, our two operands, and I'm going from right to left until we've added all of the digit positions together, and you have your sum. And it turns out binary is going to be exactly identical to this.

So, um, let's see, we have our 22 and we also learned that uh, let's take 22 and add uh another random number to it and see what the result is. So, I'm going to take 22, which we know is 1 0 1 1 0. And let me pick another number. Uh, so we don't have to reconvince ourselves that this is true. Um, and I'm going to come all the way back up here. And we said that, uh, 1 0 0 1 is equal to 9. So, let's do this. 1 0 0 1 is equal to 9. So, intuitively, we're adding 22 + 9. And these are both the decimal numbers we're so comfortable with. We know that's equal to 31. Uh, and you know, maybe you have to to verify that yourself, but you can use your calculator here. Um, so we're going to start right to left. And before I start this, you might have a quick question. And that's uh the two operands we have, this A and B, this 22 and 9, do not have the same number of digit positions. So what do we do here? And there's something beautiful you learn that carries over and is just as true now.

So let's go back to our decimal word for our decimal world for a second. And if I gave you the number 762 arbitrarily chosen, then you know that this is equal to the same number as 0762, which is equal to the same number as 00762. And more generally, uh, any amount of zeros before our number are equal to the original number. And that's because we just ignore ignore any leading zeros. And why is this uh why can we do this if that's not clear? Um, and that's because if we expand this 762 in our exponent way, we know we have 7 * 10^2 + 6 * 10^1 + 2 * 10^0. And if we add any number of twos, all we're doing is adding 0 * 10 to some increasing power. And we already discussed why 0 * any number is equal to zero. So this 0 * 10^3 is just going to drop out. And if we had the same thing again where we had a 0 * 10^4, that's just going to drop out. So any amount of leading zeros actually has no impact on the total value of our number. And so what I'm trying to get at and took a long way of explaining is that you're able to add number you're able to add zeros to the start of a number without changing its value.

So what I'm going to say in binary is that if we have this number in binary, it's going to be the equivalent of this number in binary where we add one one or one zero. Or we could add any number of zeros and it's going to be the equivalent value in binary. So, I'm just going to go ahead and take that logic and make our two operands in this addition problem uh have the same number of digit positions. Just like that, I added a zero to the front of our number, but did that does not change the uh numerical interpretation of that value.

So, going to take a sip of water here. Let's go ahead and add these two numbers together then. So we have a 0 and a 1, which 0 + 1 is 1. And then we have 1 + 0, which is 1. 1 + 0, which is 1. 1 + 0, which is 1. And 1 + 0, which is 1. Um, and this is not that interesting. Uh, we didn't actually see carryover, so I kind of picked a bad example in hindsight, but we'll do another. Don't worry.

Um, I am going to claim that this number in binary plus this number in binary equals this number in binary. Um, and our if we did everything right, we should hope that this number is actually equal to 31. So let's go ahead and uh convince ourselves that that's the case. So uh we start with 2^0, 1, 2, 3, 4. So we have 1 * 2^4 + 1 * 2^3 + 1 * 2^2 + 1 * 2^1 + 1 * 2^0. And that's cuz we have one in all these digit positions which is just equal to 2^4 which is 16 + 8 + 4 + 2 + 1. And 16 + 8 is 24 + 4 is 28 + 2 is 30 + 1 is 31. And uh sure enough this is the exact result we were expecting.

Um, but what if I wanted to give a more nuanced example uh one where we had carryover. Well um, let's do exactly that. Let's go ahead and do 101 plus 11. Um, and I will go ahead and spill this out for you that this is uh five plus 7. Um, and we would hope that the result is then 12. And it'd be a good exercise for you probably to pause this video and convince yourself that those two numbers are uh five and seven. But uh we we need not do that for the sake of time.

So, uh, we add this 1 + 1 and we may be convinced to write a two down here cuz, you know, there's no, it doesn't sum the more than 10. We don't carry over. But remember, in in binary, we only have zeros and ones to work with. So, versus decimal where we carry over when we're going from 9 back to to zero to 10. Uh, in binary, we carry over uh when we're going from one to two, i.e. we roll it back to a zero. So, we put this remainder down here. um, we put a zero down below and then and then carry a one over and now we have 1 + 0 which is one but we have another one that we have to add the carryover and we're at two and we have the same issue as before. So we put the the carryover we put a zero below and then carry over once again.

>> And now we have 1 + 1 + 1 which is three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true.

So basically when we're adding binary numbers, if we have a zero and a one in a position, it becomes zero. If we have a one and a zero in a position, sorry, I misspoke. If we have a zero and a one, it's a one. A one and a zero, it's a one. A zero and a zero sums to a zero. And then if you have a one and a one, we know this is binary two. And so that means we put a zero over here because the two divided by two, there's no remainder. And so we just carry over a one. And then the uh interesting case that we can't generalize from the remainder of these is if we have a one and a one and a one and that means we have three. And we're going to go ahead and it's it's interesting. We we put the remainder uh when we modulo by two. So 3 / 2, the remainder is just then a one and then we carry over a one here. And uh this is our final result. And uh this is actually equal to the bi to the uh number 12. You can verify this yourself for it to be true

An AND gate and an inverter gate together to build this circuit out. So let's go ahead and see, uh, what this does. I will spill the answer for you, and then we will, we will verify that things are true. So I'm going to take our A and B, which are our inputs. I'm going to feed them into this AND gate. And then I'm going to feed the output of that AND gate into a NOT gate. This gate that we saw down here. And then I'm going to let that be the output Y. And so I have this circuit. And this is, this is pretty big. What we just did is we, we took the output of one gate and fed it in as the input of another gate. And it's, it's a small example, but we're, we're going to see more complicated ones very quickly.

So let's go ahead and convince ourselves that this is actually equivalent to our NAND gate from over here. And the way we can do that is we can build a truth table, uh, for what we have here. And what we have here is called a circuit. A circuit is what happens when you chain logic gates together. And by chaining logic gates together, we can provide, we can build circuits that accomplish more interesting things. So these are these, these, these, uh, logic gates on their own don't do very much, but by chaining them together, we could actually have them do really interesting things. Uh, and I mean, the end goal is chaining them together in such a way that we build an entire computer. Uh, and that is totally possible, as I will try to convince you over the next few hours.

So let's go ahead and build out our truth table. We have two inputs and one output. And let us see, uh, we know our, our output cases are as follows. I'll change up the order here a little bit for the second and third rows. So when A and B are both zero, well, we have A is zero here, A zero here. Zero and zero is zero, cuz not both of them are one. And then we invert it and, uh, produce a one. So we end up with a one as the output of our, our circuit when the inputs are both zero and zero. And, and let me change color here just so it's easier to follow. Then let's suppose we have zero and one. Then the AND gate's still going to output a zero because not both the inputs are one. But when we invert it, it becomes a one. So, uh, this is a one here. And if I flip this, uh, if I say that B is going to, if A is going to be, sorry, I did that backwards actually. Um, I showed you, let's see, I showed you zero one. Oh, no, no, I did that correctly. Now I'm going to show you one zero. And we know the output of the AND gate is going to be unaffected. It's still going to be a zero. But then when we invert it, it becomes a one. And lastly, uh, if we have a one and a one, then what happens is our AND gate outputs a one, but when we invert it, it becomes a zero. And so we, we have this truth table right here. And I'm going to replace this with white now that we're done drawing. What we would expect is that if this circuit is equal to the NAND gate, then the truth table should be identical. And if I scroll out, we can see that the truth tables are identical. Uh, you can compare each of the four rows against each other. Um, I know I've swapped the order of the middle two, which I shouldn't have in hindsight, cuz it's a little confusing now. Uh, but I was trying to illustrate the point that the truth table doesn't matter what order the inputs are in, as long as you cover all the possible inputs. Um, but in general, I've shown you how to build a circuit by chaining logic gates together and that you can verify that two circuits are equal by showing that their truth tables are identical for every pair of input combinations. So this function, this circuit is a function of A and B, and it's going to equal Y. And so is our NAND gate. And it turns out they're actually, they're the same function, um, because they always equal the same value. And so this is, this is pretty interesting. And, uh, we could, every time we, we could avoid using the NAND gate just by by drawing this. But it turns out that we use a NAND gate enough where we, we want to give it its own gate. Um, because it, it kind of, when we have these big circuits that chain a lot together, it, it becomes a little bit more convenient to have, uh, simplified ways to represent things we use frequently. And we will see this later on. We'll design some interesting circuits and then we will just, uh, demark them as a new type of, of, of gate, or maybe we'll say, uh, a triangle represents this circuit underneath the hood. Um, but, but don't think about that now. That's something that, uh, is more of a future concern.

Let's try another circuit. So you've seen, um, a circuit now that has two inputs and one output. And so for logic gates, I, I made a claim. I said a logic gate has, uh, at least one input and it always has exactly one output. A circuit has at least one input, but it may have multiple outputs. And we'll see this later, um, when we actually try to build more meaningful circuits. Let's try build something, uh, and let me draw a circuit, and then we will build a truth table for it and, and analyze that truth table and see if we can derive some meaning for that circuit. Okay, this is our circuit. I'm going to take a sip of water while you look at that. And I would like you to notice that there's three inputs and one output. And, uh, we have an inverter, a NOT gate, right here. Then we have two AND gates over here. And then we have an OR gate over here. That's just because, uh, you know, it may actually be useful to screenshot this as you follow along, or just, you can Google logic circuits and it'll be there. It's also in the website I have linked below. Um, but we have a, a circuit now and, uh, this may seem like a random circuit, but it actually does something a little bit interesting. Um, so, [snorts] I will spoil the fun and say that this is a selector circuit. So if you put some value of A and B, uh, put some values in A and B, then C serves as a selector where if C is zero, then the output, so I'll write this out. If C is zero, then Y is going to equal to A. And if C is one, then Y will equal B. So C effectively controls what flows through as the output of this. So I'm going to move this over here. And let's verify this by building a truth table for our circuit. So this truth table is going to be a little bit longer. There's actually gonna be eight different values we can pass in. Um, so I'm going to come here. We have eight different values we can pass in. Our output's still Y. And, uh, I will write out all the eight values. Uh, it may be interesting to you where I'm getting these values from. Uh, but you you need not worry about it. Um, I'm just, you'll get more comfortable enumerating all these values out the more you do do it on your own. Um, it's getting a little messy because I have not the best handwriting. Um, okay. So, uh, believe me, please, when I say that these are all the possible values of A, B, and C. If you do not believe me that I challenge you to pause this and try to generate a, a new, uh, combination of A, B, and C that's not in this table. And if you're curious where this, this comes from, why, how do I know how many are in, how many different values there are? Well, if we're looking at A, B, and C stacked next to each other, um, they're all either, they're binary values. They're binary digits. So, there's two different values that can go into each of these digit positions. And so I multiply the different possibilities together to figure out the total number of combinations. So in that case, there's eight. Uh, and that's because, um, for each of the position, we can either choose a zero or one, uh, zero one. And then we multiply that by the number of ways there are to pick out the remaining digits. Um, and we can apply this process over and over. Um, but I'm not going to get into that, cuz I think it's a little mathy and, uh, that's actually a study of combinatorics, which is probably a little too, uh, technical for what we're getting into today.

But let's go ahead and trace through this. So, I'm going to switch my pen back to red and I'm going to make it a little bit bigger here so it's more readable. Our first example, um, I'm going to zoom out here, is I'm saying if A and B are both zero and my claim is that if C is zero, which, or C is one, then our output should be B, which is zero in this case. Um, but it's a little hard to distinguish because they're actually both zero. But let's, let's verify that it's not one for sure, and that'll have you partially convinced. So, uh, what we do right here, um, is we have C, which is one. And so, that means that we invert it. It's going to be a zero here, and it's going to be a one here. And then we have these carried through from our, our original logic gates. And so, for the first gate, we know zero and zero is zero. And zero and one for the second logic gate, still zero. And so, we have two zeros flowing into an OR gate, which means the output is zero. Um, so we traced through the circuit and we, our claim is verified so far. Uh, C is one and the output was equal to B. But you should be confused because how do I know that it wasn't equal to A? Um, and or just, it just happened to be zero independently of what B was picked. Um, and, uh, that's a great question. And let's actually toggle whatever. Let's set B to a one and see what changes. So, I'm going to erase this. Um, and everything I've left on the screen so far is un, is unaffected by our changing of B from a zero to a one. But now, if I set B to a one, then this AND gate over here is going to output a one, which means this OR gate's going to output a one. Uh, and, and now we, we do have a little more substance to our claim. So, we have the case here of, uh, A is zero, B is one, and C is one, which is over here. And we know this output's going to be one. Um, so I'm going to keep going through these examples. But what should be a little bit apparent by by now, uh, is if you look at these AND gates, we know that for an AND gate to output one, both of its inputs need to be one. And C goes to both of these AND gates, but one of them gets the regular C and one of them gets the opposite of C, the inverted value of C. So we know that the one that's getting the, the, uh, we know one of these AND gates can never fire because by virtue of C getting C going to one gate and NOT C going to the other gate, then the gate that gets the zero version of C, whether that's the inverted version or not, can never output a one because it, it's both of its inputs can't be one. So for example, if I, if I set C to one here, then this is going to be a zero. So this, this gate can never output anything but a zero. So this gate effectively gets silenced and then the value of B can just flow through this gate and it gets to this OR gate where it's just going to go through because the OR gate has a zero here. Um, and, and it may take a little bit of time for you to rationalize this. So, so pause it. I, I would recommend you pause things actually and fill out the rest of the circuit for yourself mentally, or pause it as I work through some of the cases.

So now let's look the example, um, and I, I miswrote this here. There should be zero zero zero where everything is zero. So, uh, zero zero and then we have a zero here, which means a one comes here and a one comes and a zero goes there. So in this case, uh, both AND gates output a zero. So our Y is also going to be a zero. Um, [snorts] and we kind of have this rule where we said if, if C is zero, then Y is equal to A. And that, that's still the truth because C is zero and, and we have Y equal to A, which is still zero. Okay. Uh, now let's look at a more interesting case. So if we have A is zero but B is one, then let's look at the first case where, uh, C is zero. So if C is zero, then this is going to be a zero. So this gets cut off because we can't output anything but with a zero. And then this is a one. Uh, but we know one and zero is zero. But this is still A's value flowing through because if A was a one, a one would get through. And A is a zero and a zero goes through. So A's value is, is flowing through here. That's what I'm hoping you can see. And then we have a zero or a zero, which is, is a zero, which A's value still flows through because if it was a one, then that's sufficient for this OR gate to activate. So we have C is zero and then in our case, A goes through, which is, is kind of what we would hope to see. And I am going to, uh, quickly work through the remaining cases because I said I would. So let's do, uh, A is one and B is zero. A is one, B is zero. Uh, the first case will start with C is zero. So then a one goes through here, a zero comes through here, a zero and zero is zero, one and one is one, and then a one or one is one. And you can verify this. This meets what we would expect of the rule. And now if we flip the value of C to get the next row in the table, then we have a C is one, this is zero, this is one, um, and then we have a zero coming through here, a zero coming through here, which means we output a zero. And this, this rule still holds. And now let's look at the very last case, uh, when both the inputs are one. So if both the inputs are one and C is a zero, um, start with that case. Then this is a one. This is a zero. This outputs a zero. This outputs a one. And that means we output a one. I'm going intentionally fast here just because, uh, I don't want to waste too much time. Our very last case we switch C to a one. And now we have a zero going to this gate, which is effectively cutting it off. And we have a one going to this gate, which is letting B's value flow through. And we have zero or one, which is one. And now we've completed this truth table. And let me erase what I have. And, uh, hopefully you can, you can verify this and see that, uh, this claim I've made actually does hold. Um, if C is a zero, then we let the value of A flow through. And if C is a one, then we let the value of B flow through. So we've built what we called a selector. This is called a selector. And hopefully my goal in showing you this was not to waste your time, uh, but to show you a circuit that we are going to revisit in the future, um, but also show you that we can chain these logic gates together to do pretty interesting things. Um, this is a, a somewhat of a trivial task, but it's, it's actually not that trivial. It's, it's trivial because I gave you the solution, but if I asked you to invent this on your own, it might not have been apparent as to how we, how we do this. Um, so yeah, this is a, a, a brief overview of circuits and how we can chain logic gates together and build circuits.

Okay, so what we've now accomplished is, I clear my screen here. I showed you what a logic gate is. I showed you what a truth table is and how to derive a truth table by looking at either a circuit or a logic gate. And then I showed you how you could compose logic gates together to build what we call circuits that encapsulate more meaningful behaviors. And I also made this crazy claim that we're going to build an entire computer out of just logic gates. So before we even did that, we talked about binary. And what I would like to do now, as I promised, I would like to bridge those two different concepts together. So, we discussed binary and we discussed logic gates. Um, but I haven't yet told you how they relate to one another. That was a bad arrow. And what I'm going to do in this part of the video is, is bridge this together by showing how we can build a circuit, i.e., chain some series of logic gates together to build a circuit that can add binary numbers. And this is going to be cool because we have a way of going from the decimal numbers we know to binary numbers. And then I'll build, I'll, we'll end with a circuit that can add two binary numbers together. And in the real world, these logic gates act incredibly quickly. If you change the inputs on an, on an AND gate, for example, the output will, will settle. It's what we call propagate very quickly. And in this way, if we, uh, assume that there's no time for us to convert from decimal to binary, which is obviously not true. But if we just assume that we have a long list of binary numbers and we wanted to add them all together, then doing it with a calculator, I guess say we also have a decimal equivalent, then adding those numbers up with a calculator or manually, should I say, adding those numbers up manually as a human is going to take some time. Whereas we could build this circuit that that outputs the value once you put the numbers in almost immediately. And these logic gates operate very quickly and this will be a useful circuit because adding numbers is something we would like to automate as a computer. At the end of the day, you may have heard some saying that a computer is a glorified calculator. And the further along you get in this video, the more convinced you may become that that is the reality. And it is true. Computers operate on numbers and they are able to perform arithmetic on numbers incredibly quickly. And in, in that sense, a computer really is just a glorified, glorified calculator.

But let's start with the simplest case. I previously said when we learned two's complement that we had to assume that every number in binary is going to be the same number of digits. I also then said that our computer is going to be an 8-bit computer, meaning that we use eight digits to represent every binary number. And I, I should have mentioned this earlier, but I've been, I've been trying to avoid it just in hopes of trying to avoid throwing too many words at you. Uh, bit is just a zero or one. It's synonymous with a binary digit, uh, bit. And we talked about how most modern, a lot of modern computers use 32 bits or 64 bits or even 128 or 256 to represent their numbers. We're going to build an 8-bit computer because it's enough for us to represent some numbers, uh, and build these circuits out without using an incredible number of logic gates. But, but at the end of us building the computer, it'll be incredibly easy for you to understand how we could scale it up to be a 32 or 64-bit computer, something perhaps, let's say, more modern. And the reason I won't do it is because, uh, I am drawing these logic gates out by hand and, and drawing something 64 times every time we want to have a number. This will make more sense later is painful compared to eight, which is still inherently repetitive but bearable.

So let's start by building a circuit that does one-bit addition. So one-bit addition means we're adding binary numbers that are just one digit position. And, and so this is pretty easy. If we're just adding two numbers, we know that the, the two, uh, if we're doing the addition tables, we could have a zero plus zero, a zero plus a one, a one plus a zero, or a one plus a one. And I'm setting these up in the way we, we normally do addition. And so we know the output in this case is a zero. Uh, in this case is a one. In this case is a one. And in this case, we have a zero here, but we carry over a one. And so the output's one zero. And this makes sense. We're, we're what we're saying here is that zero plus zero is zero. And then here we're saying zero plus one is one. And then here we're saying one plus zero is one. And here we're saying one plus one is two. Because in, in binary, this is, uh, two to the first plus two to the zero, which is just two to the first, which is just two. So we'd like to build a simple circuit that can do this arithmetic for us. So if we set A to be one number and B to be the other, we should get the output. [snorts] And what we've noticed is that we have two inputs here. So let's try do this in reverse. We previously looked at a circuit and then built a truth table for it. Let's in this case start with a truth table just we have our, our consolidation and then try guess what circuit might match it. So in our case, our two operands, operand meaning the numbers that we're adding together are A and B. And we'll let out our output Y be our sum. And for [snorts] now, we're going to ignore this carry bit. We're just going to say the, the trivial, uh, one-digit result. And so in that, in that case, I'm going to kind of draw a red circle on this cuz it's something we're going to have to revisit. Um, because when we do add one and a one, the output's not going to be zero, but we're just going to design our circuit to only have one output for now. And we'll come back and, and, and add a second output that could be used to represent that carry bit. So if our truth table may look something like this and we know the output in each of this case is a is as follows. And so what we'd like to do is build a circuit that that encapsulates this truth table. And now what you may be recognizing, if you paid close enough attention, is that this truth table over here is, is, uh, very similar to the one I had for the exclusive OR gate. And it's not just that it's very similar, it's actually the case that they are identical. And this is, uh, something that works out just conveniently. And this exclusive OR gate can be used, uh, to do our, our little bit of a one-bit addition here. Um, so as it, as it turns out, uh, if I let A and B be our inputs, then we could feed it into this exclusive OR gate and the output Y, uh, is, is holds. And so this does our, our addition for us. You could fill this truth table out again if you don't believe me, but that's pretty cool. Um, I know we made this huge oversimplification. We're looking at one-digit numbers, but it's cool that this one gate can be used to perform, uh, this one single-digit position worth of arithmetic.

But what we're missing out here is that we have in the, in this last case where this red is on the screen, we have it's possible that if we're adding a one-digit number, two one-digit numbers, that our output could be two digits. So if we're adding two one-digit numbers, a one-digit number and a one-digit number, our output doesn't always have to be one digit. It could be two digits, as we saw here. So what we need to do is update this circuit to accommodate for this. So what we could say in each of these examples that only have one bit of output. I talked earlier about how we can pad with zeros. So I'm just going to pad each of these scenarios with a different zero. I'm going to do a little bit of separation here. And now let's say we have a circuit that takes in two inputs and produces two outputs. The two outputs will be the two bit positions. And what we're going to do is, we're going to call this one the sum bit. Sorry, I wrote that weird. This is the sum bit and this is the carry bit. And, uh, I'm just going to happen to call it that accordingly. Um, so what I'd like to do then is update our truth table and, and add in these additional values. So our carry bit and our sum bit. And it's just going to be the exact same values that we had as before. Um, but the interesting thing is now that we're able to represent correctly the, the value of what happens when we add one plus one. We can represent two. And that's because, as we talked about earlier, we can't represent two with one binary digit because that's just not possible. And you also may be wondering what about this two's complement? Uh, let's just ignore it for now. Ignore two's complement because we're, we're just going to assume that we're working just with positive numbers. So ignore that rule where you multiply the leftmost digit by the negative one of its, [clears throat] weight. And then over here, let me just write a note that, uh, we're going to say S stands for the sum position and C stands for the carry position.

So now what we want to do is build a circuit that has two outputs. One for the carry bit and one for the sum bit. And [snorts] well, we already knew how to build the sum bit. We said the sum, or the carry, the sum bit, sorry. Uh, we already knew how to build this out and I've made a mistake here. There should be a zero. We already knew that the sum bit is going to be equal to the exclusive OR gate. So, let's recreate that. I shouldn't have erased it, but I did. Uh, just cuz I wanted to have us a fresh slate for us. Um, and let's say that the exclusive OR gate right here gets the input from A and it gets the input from B. And this is going to output. Let's put this over here so we can get it in the left to right. This is going to output the sum bit. And then now let's look at this carry bit. If we look at the carry bit, it always outputs zero except for when A and B are both one. And if you, uh, pause, pause for a second here and try to think of what gate this reminds you of. And the answer is that this is equal to the AND gate. This has the same exact truth table as our AND gate up here, the [snorts] very first gate we talked about. And this works out really convenient, uh, because it means that we can just steal the AND gate and use it to represent this, uh, C, this carry bit position. So if I just have an AND gate, then the, uh, output, sorry, let me write this over here. So we have the carry bit here, um, and let's have the sum here. here. So that, let's just read it left to right as we, we did up here. But let's go ahead and chain these inputs in. So when A and B are both to one, then we should have this carry. And I apologize because, uh, I accidentally inverted this C and S, which I apologize for confusion. That's the sum bit, the one that we saw we could already use the exclusive OR, and then we wanted to add this carry functionality, which we saw the AND gate lets us do. And I, uh, now you have built a circuit that, uh, takes two one-bit, i.e., one-digit binary values and outputs the sum of them. And I'm not going to trace through every single example, but, uh, I will do one. Let's say we are adding one and one, then we can look at this gate. We see A and B are going into both of these gates. So one exclusive OR one is zero. But then one AND one is one. Um, and so we have this, this, this, uh, carry. So our result, we know is in the order of, we read it left to right, which is carry, sum. And so we have a one for carry and a zero for sum. And if we interpret this as a binary value, then we have one zero, which is two. So this is really interesting. We've, we've learned about binary. We thought it was useless, but, uh, we actually then learned about logic circuits and built a logic circuit that can add two one-digit binary numbers together. And this is really interesting. And I will let you suggest that you pause this video and trace this circuit through every case and make sure you really understand what's happening here because what's really happening is that if we look at this, uh, there's one way to justify this truth, this, this circuit is by the truth table. But what I like to do is I like to have an intuitive understanding for why these circuits work the way they do. And I think I kind of did a, a what I would hope was an explanatory job with the selector circuit we previously looked at. But for this example, let's try to do a little bit of reasoning. Um, there's only going to be a carry if we are adding one and one. That's the only case there's a carry. So if there, in any other case, the carry is zero. So we can use an AND gate kind of to represent the carry logic. So whenever there's a one and a one, then this AND gate triggers, and that's the only scenario in which we carry. And then for this exclusive OR, what that's saying is if we're adding zero and zero, then we don't want anything to be outputted for the sum position. And if we're adding a one and a one, we also don't want anything to be included for the sum position because there's going to be a carryover. So we only want something to be added if there's just one one of the, if, if one of the two inputs is a one. Exactly one of the two inputs is a one. And that is just the definition of the exclusive OR gate. So this works out perfectly. So, we've built, uh, this circuit and it turns out this circuit has a pretty, uh, it's famous enough where it has its own name and this is called the half adder. And this is cool because if we're adding two binary numbers, zero one zero one zero or one one zero one one, then this circuit lets us add each of the corresponding digit positions together. Right? And when we're adding numbers in binary or decimal for that case, we do it as we can think of, we actually divide up the work. We look at each digit position at a time. We start with the rightmost digit position, do its work, and then put the sum below and then do the next digit position and put the sum below. And this right here, this circuit is effectively doing that for one digit position.

Now, there is a little bit of a shortcoming to this. What we'd like to do is to be able to have these half adders. If we want to add to, in our example, we have two five-bit values, five-digit values. If we wanted to add them together, we would like to use five half adders and put them next to each other. And so we could write in all the operands values on, uh, each of the A lines and then all the other ones on each of the B lines, um, and, and have a circuit that could just produce the output immediately. But this, uh, this unfortunately is missing something. And I, I, I would actually take it as a challenge to pause the video and try think about why we can't do what I've just described. Because in theory, we've built a circuit that can add one digit position. So why can't we just have a bunch of these circuits next to each other? Why couldn't we place five of these next to each other and let that be used to add the five-digit positions? And I will spoil it now. The issue is exactly what happens when we carry over. So let's look here. Let's do our little example. So we have a one and a zero. If we fed this into our, into our half adder, then we would get the output zero one. So we'd have a one for the sum and a zero we would carry over. And so that works out fine. And now if we do the input one one, if we suppose we had a half adder that did this, this computation, we know it would output a zero for the sum bit. So a zero would go down here and then a one would go up top for the carry bit. And now the issue comes when we run into this digit position here because we have three values we need to add for this digit position, but our half adder only adds two different values. So there's an issue in that we output the correct number of values because for each digit position we have one, we have two outputs. We need to know what goes down here and if we carry over to the next position. But our fatal shortcoming is that we are missing the scenario for when there is carryover. We actually have three digits we want to be adding. And this is something that we are not accounting for in our circuit. So maybe you guessed by the name, but half adder, uh, lets us do half the adding logic, but what we're looking for is a circuit called a full adder, which lets us do the exact logic. So what we'd like to do is, we'd like to have our A and B, but we'd also like to add a new line for carry in. And so what we'll do is we're going to have to build a new circuit that can kind of handle this logic. So why don't we try start with the truth table for this? We have A, B, these are our two one-bit values and there could be a possible carry in. And I'm not going to use a, uh, I want to distinguish because our output over here we had a C and now we're going to have a C as the input. And that's because there's a carry in and a carry out and they're fundamentally different, as you know. So our output now is going to be carry out. I almost wrote in and then the sum. So we still have two outputs, but now we have three inputs. So, let me, uh, go silent for a moment as I populate this truth table. [snorts] Okay. So now let's take this truth table and think about what this means. So now we're adding effectively because of the carry in bit, we're adding three, three one-digit values. And again, we're still ignoring two's complement. Uh, we'll come back to this later, but let's not overcomplicate things now. And let's see what happens. So, uh, I'm going to go ahead and, uh, it's, it's easy to do these quickly because, uh, we're working with zeros and ones. So zero plus zero plus zero is, these are all binary numbers. But remember that, uh, zero in binary is equal to zero in base 10 and one in binary is equal to one in base 10. So we can kind of ignore, we don't need to convert between binary because we don't need to convert these binary operands, these binary inputs to our circuit to decimal because for zero and one, they're equivalent, which just works out perfectly for us because we don't have to overthink, but it can be tricky to sometimes wrap your head around that. So we're adding zero plus zero plus zero. So we know the output's just going to be zero. Um, i.e., uh, there's, there's, we're adding zero. We need to represent that in two digits. The output zero. The, uh, if we're adding a zero and a zero in a digit position, but the carry in is one, then we know we output a one because that's what we sum. And then there's no carry over to the next digit position. We know we just, we just throw a one down below. So that's fine. Then let's look what happens if we're adding our A and B, which are zero and one in the next row. And then first off, we have no carryover. So if we're just adding a zero and a one, then we sum a one with no carry out. But if we have a carry in, then we have one plus one, which is two. And two divides into two exactly. So there's no remainder. And then we do have a carry out. So in this case, we have a one for the carry out, but a zero for the sum. And, and maybe rework that for yourself if it's unclear what's happening. But you may need to go back to the earlier part of the video where I showed you how to do addition of binary numbers. Let's move on to the next case, uh, which is when you have a one and a zero. And the first one, there is no carry-in. And this is kind of what we looked at before. You just have a one carries down and there's no carryover. Uh, so this is a zero and a one. But if you do have a carry-in, then, uh, you have one plus one, which is two, and two divides perfectly into two. So the remainder is zero and then we carry over a one. So we have a one here. And then the last case is, last two cases are when we're adding a one and a one. So if we don't have any carry-in, then one plus one, we already know is two. So the output is that we carry out over once and then put a zero below. And then the, uh, edge case that is, is bringing us here, uh, is this one one one. Um, and that means one plus one plus one is three. And that means we put the remainder down below. So three would, the remainder one divided by two is one. And we have the carryover. Um, and so we have, we have three up here. This is actually three in base 10. And you know this makes sense because this is in binary. We have one one one two in base two, which is equal to three in base 10, if you do the conversion. Cool. So, we have our truth table. Now, let's think about how we can actually build this circuit. [snorts] And so, what I'd like to do for this is go ahead and, I think this is a difficult one to build because we have three inputs, which is more than two. So we have eight different cases we need to handle and we have two outputs. But I would like to take a logical approach to building this, not just spill out the answer and let you prove it yourself, but kind of give the answer, um, build up and explain why it is we're doing what we are doing. And so the way I would think about this is, uh, let's look at each of the outputs separately. We could build a separate out, a separate circuit for each output. We could think of building a separate circuit for each output. Um, and that's because, uh, they are two different outputs. We could build two different circuits. Uh, one circuit that takes A, B, and C in and outputs C out, and another circuit that takes A, B, and C in and outputs S. But, uh, this would be inefficient because, uh, computers have to be physically built. This computer that we're going to build has to add numbers. They have to be physically built and logic gates cost money in the real world to buy. Uh, they are incredibly small. Your computer has trillions of them, but they do incur some cost. And so we would like to design a circuit that minimizes the number of logic gates used. When we're building our computer, we would like to minimize the amount of logic gates used. And, uh, an easy way to minimize those is to try combine the logic for these circuits. Don't build a separate circuit for the carry out and the sum. Just, just do it all together.

Okay, let's start by thinking about the sum bit. So if we stack this in the, uh, vertical kind of notation that you're used to and that we've kind of seen throughout this video multiple times now, we're interested, we know this is the sum bit. We know this is the carry, carry out bit, and the carry in bit comes up top, and this is per bitwise operation. We're just looking at one vertical digit position. So let's figure out each of the definitions in which the sum bit is going to equal one. So if we ignore this carry-in bit, then we know the sum is going to equal one as long as either A or B equals one, but not both of them, because if, so if neither of them equal one, then we, we output nothing. Uh, in the case where it's a one zero or a zero one, then we just output a one for the sum, but if they're both one, then we actually output a zero and then the carry out is going to be what's equal to one. So in the case where carry-in equals zero. So let's, let's try make a rule here. So if carry-in equals zero, then we want exactly one of A or B to be true, then then sum is going to be exactly A exclusive OR B. And, uh, recall what exclusive OR is from earlier. Exclusive OR says output a one if either A and or B is true, but not both of them. So this is exactly what we're going for because if A and B are both zero, the exclusive OR of those two values is going to be zero. If A and B are going to be one, they're both one, then the exclusive OR is going to be zero, which is synonymous with the sum in these two cases. And for any of the other two cases, we have one of A or B is equal to one and the other is equal to zero. And that's going to output a one, which is what we'd expect. So we've kind of built this rule out where if the carry-in is zero, then the sum bit is equal to A exclusive OR B, and we have the exclusive OR gate. So we can kind of build that out. Uh, but what happens, we need to complete the rule then if the carry-in is one. So then if, if I clean up the screen a little bit here, but if carry-in is equal to one, then what is the sum going to be? And for this one, we can actually probably get a little more context out of looking at the truth table. So, uh, in this row, carry is one. In this row, carry is one. And we have four rows where carry-in is equal to one. And we can see that in this case, uh, sum is one because A and B are both ones. In this case, sum is zero and only one of A or B is a is a one. Over here, we have sum is zero and it's the same condition. So it looks like when it's just one of A or B, i.e., if we have A exclusive OR B, then sum's going to be zero, and then if we have not that, then it looks like the sum's going to be one. So we can actually draw this rule up where if, if the carry-in is one, then S is going to equal to not, so I'll do like negative to represent a negation, A XOR B. And, uh, this is probably a good time to pause this and, and, and verify this is true, that is, if you're interested in in knowing where this full adder circuit that I'm, I'm going to design comes from. If you don't really need to understand that technically to move on, but I just thought your inner curiosity might be satisfied if, if you had a more complete answer.

Let's let's let's build this out as a circuit then. So our our inputs, um, and this is just for, uh, just for S. So if our inputs are A, B, and carry in, then, well, if C in equals zero, I'm going to go ahead and spoil the most efficient way to do this. It is probably a good practice for you to try to implement this on your own, but, uh, I will go ahead and, uh, spoil this.

So what you actually end up doing, uh, is for the first part, we will use an exclusive OR, which isn't that surprising because exclusive OR was there. And then we're going to actually output this into another exclusive OR, and the output of that exclusive OR is going to be equal to Y, which is, you know, let's not even call it Y, let's just call it the sum. That's what it is. And the other input of the exclusive OR is going to be this right here, this carry-in.

And so what this, what this says is, if carry-in equals zero. So if carry-in equals zero, then the output of this exclusive OR right here is just going to be whatever flows in. So whatever flows in, uh, will just flow straight through. And that's because if we put a zero on the top line, then zero exclusive OR zero is zero. And if we put a one up here, then zero exclusive OR one is one. So, uh, if C in, if the carry-in is zero, then whatever comes in here will be the output. And so what is it that comes in here? It's A exclusive OR B. So that's what we've built out right here. We've shown that when the carry-in is zero, then the output is equal to this gate, and this gate is A exclusive OR B.

Now, if carry-in is one, let's see what happens. Carry-in is one, then the output here will be the opposite of whatever comes in, because if, if, if we have a zero coming in here, then zero exclusive OR one is a one. But if we have a one in here, one exclusive OR one, well, that's both inputs are being on, and that's a zero. And so it kind of functions as a, as almost a negator in this context. And, uh, we know that whatever, so we, we know that's the, the negation of whatever is coming in here, and we already showed that whatever is coming in here is A exclusive OR B. And, uh, as it turns out, this is, this is the most efficient way to implement this in terms of minimizing the number of gates that are being used. So that's how we derive the sum bit.

What we're then interested in is the carry-out bit. So I'm going to erase what we have right here. And again, if you need to pause the video and, and convince yourself this is true, then now is a great time to do that. We have the sum bit. Let's look at this carry-out bit. We have this carry-out bit which is going off in a few interesting cases. And so we intuitively know that we're, if we're, if we're stacking numbers, we can look at it this, this visual approach again, where we have our A, B, and then we're adding them, and then we're also adding a carry-in. So, so then if we look at this right here, if A and B together sum to anything greater than one, then we're going to have to carry out. So, if, if A and B are both set to one, then we're for sure carrying out. And it doesn't even matter what the carry-in is in this case, because we know, uh, if the carry-in is zero, then we output 1 zero. And if the carry-in is one, then we output 1. But in both of those cases, we're carrying out. So for, for determining carrying out, if, if A and B are both equal to one, if A and B are both equal one, then we, uh, we know that carry-out is going to equal one. And that's not the only case here. So, uh, that would cover in our, in our truth table, that would cover these two cases right here, A and B are both one and we carry out. But notice that, uh, we have two other cases where A and B are not both one, but we still carry out. And what happens here? And that's what happens when we only have one of A or B. So A or B, but we also carry in, cuz then we have one plus one effectively, which, which is a carry-out 1 zero. So then if A exclusive OR B, i.e., if there's just one of A or B is set and carry-in is equal to one, then we carry out. So these are our, our two conditions for when we actually carry out.

And, uh, let's go ahead now and, and see how we can build this up with logic gates. So we, we, it's obviously we're going to need some AND gates. So, uh, let's start with this first rule. If A and B both equal to one, then we carry out. So I'm going to add an AND gate down here. And I'm just going to feed whatever A and B's values are into this gate. And, uh, we will start by claiming that this is the carry-out. Uh, so we know that if A and B are both equal to one, then we do carry out. But there's another case, uh, it could either be that, or if we have A exclusive OR B and a carry-in, then we also carry out. So there's actually two cases. So let's, let's implement the second case. Um, and I'm going to extend this line just because it's going to get a little messy here if I don't. Uh, the second case is we need to know if there's A exclusive OR B, which we have right here. So we can reuse this logic gate, and this is what I was talking about with optimizations. So if we need A XOR B, so I'll just bring this down. Um, and we have a carry-in. So we can just bring this down too. And this is another AND gate. Uh, then we're saying that this should also mean we carry out. But we want to carry out when either of these lines are a one. So let's join them with an OR gate. We have a gate that already handles this. This gate will trigger if either of the inputs is a one, and that's an AND, not an OR. Here is an OR gate. And we can call this carry-out. And this, uh, as it turns out, is what we call a full adder. And I've done a better job of drawing this up here. So let me go ahead and bring it down, and let's just look at this drawing, which is not as, as painful to look at as the one I, I have provided. Uh, so I will respectfully, uh, move this out of the way. Okay. And I'm also going to do a little cleanup here just because I'd like this to be referenceable later in case I need to. But this circuit right here is a full adder. And, uh, this is another great opportunity. Let me go ahead and erase this to convince yourself that this is true. Uh, if you would like the exercise, go through, take this circuit. I'll zoom out the perfect amount. Uh, pause this video and for each of the rows you see in this truth table, compute what the output of the circuit should be and verify that it's equal to what you see on the right-hand side over here. If it's not, then there's something wrong with your logic, or I made a mistake in this video, which I will hopefully correct in the description, or someone will point out in the comments if, if that, if someone ever watches it.

And what we have is this really cool circuit, which, if we're doing some sort of binary addition, then can correctly do the addition for each one of these, these vertical positions. So for each digit position, this full adder can perform the correct addition. And where we're going to go with this is we're actually going to build a circuit that can add, uh, 8-bit numbers together, because we said our computer is 8 bits. So let's, let's get back to the realm of our computer. And that circuit's going to work by us effectively having eight full adders together. And we're actually going to chain them together because the carry-out from this adder right here should become the carry-in to this adder. And then the carry-out from this adder should become the carry-in to this adder. And then the carry-out from that adder should be the carry-in to this adder. And so on and so on. And it might be a little bit vague what I'm trying to say, but hopefully at a high level, you understand that the, the carry-out from this position right here becomes the carry-in over here. And then the carry-out for this sum becomes the carry-in over here. And we've built this generalized circuit which can handle any of the possible input combinations and correctly give us the, the sum bit and the carry-out bit. And now I hopefully convinced you that we've been able to tie together the first fundamental concepts we learned in this video, uh, that being binary and logic gates. We now see a bridge between these seemingly distinct concepts, and we're going to work on drawing them together. And so we're actually going to work on building our first part of the computer, which is called the ALU, the arithmetic and logic unit. And that's going to be responsible for adding and subtracting numbers. So [snorts] I will, uh, go ahead and move on. Now's the last chance to pause this and just make sure you understand everything that's on the screen. But we'll move on and see how we can build on top of these full adders and combine them together to build a circuit that can do more non-trivial addition, because right now this is trivial. This adds, this adds technically it's meant to add one digit position together, but it could add three binary numbers, three binary digits, should I say, and, and tell you what the output's going to be. And you should also be able to convince yourself that, uh, for any three binary digits, the sum of those is going to be somewhere in the range of 0 0, which is zero, or 1 1, which is three in binary, uh, three in decimal, one in binary. And you should be able to see that this fits within two different, uh, bit positions. So there should be no doubt in your mind that for whatever values the inputs are, we are able to correctly represent the output without any loss of memory or information representation.

Okay. So before we actually do the, uh, expand this out to multiple bit addition, let's go ahead and, and give some notation so it makes sense. So I guess the example we just built out, we did something along the lines of A and B, and we get from that a sum, and then we also possibly get a carry-out, carry-out. So there's, there's, there's two inputs and two outputs for each digit position. And this happens in regular addition as well as, as well as binary addition. So if I give you two numbers, say 74 and 83, then we could say that for this digit position right here, the sum is seven. And then there's no carryover. So we'll just say the carry, the carryover is zero. And then for this digit position right here, the sum is five and the carryover is a one, which comes down. And the same thing happens in binary. So if I gave you one zero and then one one, then here when we're adding this digit position, we sum a one, and then there's no carryover. So we can implicitly write a zero for the carry. And here we have a sum and a carry, which comes down. So that's just a little bit of recap.

So now let's say we want to have two-bit numbers, we want to add. That's what I said we would build up to now. So let's give some notation. So A and B are now our two operands, our two bits. So let's, let's give them indexes to make this more apparent what's happening. So we can say we have A2 and A1, and we're adding it to B2 and B1. And then from this, we would get a sum down here. And we're actually going to get two sum bits. So let's have a way of distinguishing them. And I think it makes sense naturally to give them the same indexes that we did for the, the operands. So we get a sum one, and then we get a possible carryover one. And then for this digit position, we get a sum two, and possibly a carryover from two. And if that's the case, then we, we carry it down. And again, carryover is either going to be a zero or one. So it makes sense that if we have the zero and then some binary digits, it's the same thing as just the binary digits that we saw earlier.

And so what this means, and I'll go ahead and erase this to stop the screen from getting too crowded, is we are going to effectively use two of these full adders we've described and chain them together with these operands as so. And so what we're going to see is that the, uh, first full adder is going to take this A1 and B1 as its operands. And then we're going to treat the sum output as S1. And then what we're actually going to do with the carry-out, this C, this carry-out, uh, that we have right here, is we're going to feed it into the carry-in of the second full adder. And the second full adder is going to be operating on A2 and B2. So we can kind of see how these get chained together. And so why don't we go ahead and try build that? And luckily, because I'm drawing on my iPad, I can just duplicate this right here. And I'm going to paste it twice below. And we will give the proper notation. So let's not this I have up there. And I'm going to copy this again and paste it one more time right here. Okay. So now what I'm saying, and I think this will make a little more sense now, is let me move this over here. Okay. So if I have A1 and B1, I want to use this half adder. And let me actually, yeah, I'm going to use this, this full adder. Sorry, not half adder, full adder to do the A1 plus B1. So what I do is I'm going to feed in A1 and B1. And this is the, the, the rightmost digit of the two numbers we're trying to, to operate on. And now you might be wondering, this is a good question. What do we do for carry-in? Because for this rightmost digit position, we're never going to have a carry-in. I mean, if, if we think about it, that's where we start our addition at. So how could there already be something before that to which we could have carried into? And the answer is there's nothing. There's no way we could ever have a carry-in on the rightmost digit position. But we do know is that what we're effectively doing is A1 plus B1 plus the carry-in. That, if, if we're doing this plus this plus this, and we know that the carry-in is zero, then we're really just left with A1 plus B1. And so what we're going to do is just hardwire this right here to be a zero, because there's no way we could have carried into our first bit of addition. And then that's going to let us use this, this, this full adder we have to do exactly what we want. So now let me go ahead and erase what we have marked for these outputs. And let's say that the output of this is going to be S1. And then the carry-out. So this is carry one. We're going to feed that into the carry-in of this next full adder. And, and visually, that is the arrow we see right. Let me erase these. That is the arrow we see right here. When we add A1 and B1, we get the sum one down below. And then we may have a carry-out, a carryover from S1 from that first addition into the second addition. And that's exactly what this arrow represents. So now for this second full adder, we will feed in not A1 and B1, but A2 and B2. So now I'll throw in A2 and B2. And from this, we get sum two, and then carry two. So now you can see here that if we have, and let me go ahead and erase this because I think it's a little complicated. If we had two operands we wanted to add, and both of those operands were two binary numbers, two binary digits, then we could simply plug them into this circuit right here, and we would get the sum as something we could read from S1 and S2 combined with C2. And I should not have erased that. And this C1, it's not that it's useless, but it doesn't actually show up in our output. We use it as part of the computation, but we only care about these three for our output because these are what we actually read, and that's what we want to know. We want to know the sum of the value. We don't really care about where the carryover happened intermediately and internally. We just need to know that we make sure that we deal with it correctly when it does happen.

So let's go ahead and plug in a little bit of an example here. Uh, just to make sure that this works. Suppose I wanted to add one zero. Sorry, I wanted to add the binary numbers 1 1 and 0 1. And this in binary is going to be equal to 3 + 1. So 3 sub in base 10 + 1 in base 10. And we know we should expect four back in base 10. And we can do this arithmetic manually. And we would see that we know the 1 + 1 is a zero, but we carry over a 1. And then we know that this 1 plus one also a zero, but we carry over again another one, and then that one drops down. So we can kind of see that we would expect this to be S1, this is S2, and this is the C2. And then we know that this is, we know how A1 and A2 are structured based on this diagram over here. And, uh, sure enough, uh, we, if we plug this into our circuit, we expect to get that. So let's go ahead and do this. So I'm going to plug into our circuit. We have a one and a one. This is the A1 and B1. And then a one and a zero for the A2 and B2. And we have to start with this circuit on the right because you notice the circuit on the left. One of the inputs comes from this line over here. And that's actually the output of the circuit on the right. So we'll have to start by doing this first. So we have one exclusive OR one, which is a zero. And then we have to this right here, we have zero exclusive OR zero, which we know is just a zero. So sum one, I'm saying a zero. And that, that checks up with what we have here. And then I'm saying, let's come down to this AND gate over here. I am feeding that a one and a one. So I'm going to output a one from that AND gate. And then over here, I have a zero and a zero going into this gate. So this is going to output a zero, but they feed into an OR gate. So we're going to have a one OR zero. And that means we're going to output a one. And so that means that carry one should be one. And this makes sense because we have a one up here. And that's carry one. You know, this should be carry one and this should be carry two. So then we bring this one all the way around here. And we can do the same calculation for this full adder. So we have one exclusive OR zero, which is a one. And then we have this one exclusive OR one going into S2, which means we're going to output a zero, cuz one exclusive OR one is zero, cuz both the inputs are set. And that checks out with what we have here. And then we come down to this AND gate over here, and we have one and zero, which means we output a zero. And then this AND gate down below is one and one, which means we output a one. And then when we OR those, we get a one. And this is exactly what we see.

So this is really interesting. We have the two full adders chained together, and now we're able to do two-bit addition. We're able to add numbers that are two bits in length. But one thing you may be noticing is that this is pretty ugly to look at. We're having a lot of logic gates, and it's not visually appealing to look at. And I kind of hinted at this earlier, but we can kind of abstract this away. So instead of drawing this ugly circuit out, let's find a way that we can just represent the full adder as something easier. And let's just give it a square. Let's just say that if we have a square, sorry, a rectangle with "Full Adder" FA written in it, we just know it means a full adder. And what we really need to show is the inputs and outputs, because we now understand how the full adder works internally. But when we use it to build more complicated circuits, we don't necessarily need to see all the logic gates inside of it. We just need to be able to represent what goes into it and what comes out of it. And so we know that for a full adder, the inputs are an A, a B, and the carry-in. And then the outputs are a sum bit and a carry-out bit. And all you need to understand is that this full adder, I've, this, this rectangle, which I'm claiming to be a full adder, if we really wanted to see what was inside this rectangle, it would be this right here, a full adder. So if we assume this diagram to be true, and this is something we're allowed to do, we're, we're building our computer. So we don't want to have just logic gates littered everywhere. What we're going to like to do is build out individual components of our computer and then abstract them away in these rectangles. So what I'd like to do now is, if you understand or at least can believe that this is going to be used to represent a full adder, let's rebuild the circuit that I've drawn up here and show how much easier it is. And to do that, all we need is another full adder, which I will copy and paste. And all we now need to do is update our inputs and outputs. So, we know that we're feeding in a zero here because we don't carry into our first full adder. And then we know that this is A1 and B1. And we know that this output is S1. And then we feed this carryover into the carry-in of the next full adder. And then we're calling this A2 and B2. And then from there, we get the sum two and carry two. And look how much easier this is to visualize compared to the mess of logic gates we had above.

So this is pretty interesting. We've now learned how to do two-bit addition. So we started with one-bit addition. We've done two-bit addition, but now I'd go ahead and like to show you how our computer's going to do addition. And it turns out it's nothing new. What I said earlier is that our computer is an 8-bit computer. 8-bit computer, CPU, central processing unit. And what this means is we operate, we operate on 8-bit values. And to elaborate on that, every value we store in our computer is going to be eight binary digits long. Nothing more and nothing less. And this makes, this makes things easier. As you will eventually see, if every single component of our computer is expecting values to come in eight bits, exactly eight digits, then we can standardize a lot of components of our computer and it makes ensures a lot of consistency between the different components. And this eight, as I also mentioned earlier, is just a random number. Modern computers can use 32 or 64. And we'll, we'll, we're going to build an 8-bit computer. And then we'll eventually talk about how we can scale up to 32 or 64. And it turns out it's not that difficult. But what I'd like to do then is build a circuit that adds 8-bit numbers. So what would this look like? Every input to our circuit is going to take in A1 through A8 and then B1 through B8. So now all of our operands, we can still, we're just building a circuit that just adds numbers. But we're going to go ahead and make sure that those numbers are all eight bits. They all have eight binary digits. And so if you understand what we did up here, then it turns out the process for eight bits is not any more complicated. Instead of two full adders for adding two-bit numbers, we're just going to use eight full adders for adding eight-bit numbers. And this ends up making things look pretty easy.

So I'll go ahead and give the expanded notation just so we have something to work with. But in general, if we're adding two 8-bit numbers, what it looks like in the graphical form that you and I are both used to is we'd have A8 and then our A value has eight different bits in it. And our B value has eight different bits in it. And if you are a computer person, you may be wondering why through this point in the video I've been doing one indexing. I've been starting at index one and going onwards. Uh, even though you know that in computer science we start at index zero and move onwards. And the reason I'm doing this is because at the start of this video, I said I wanted it to be understandable for everybody. Even if you didn't have a computer science background, and to those of us who do not have a computer science background, it is my belief that indexing starting it based on one is more intuitive to understand compared to indexing based at zero. It's one of the things that I mentally had to adjust to when I started learning computer science. So, I figured it'd be easier if I just didn't make the viewer additionally bear that burden of having to mentally shift everything over by one as they watch. So, for those of you who do have a computer science background, I think it's not too painful for you to mentally put the zero indexing away and go back to one indexing for this video. And for those of you who have no computer science background, you don't even understand what I'm talking about. And this is intuitively how you would represent things to begin with. [snorts] Cool.

So, these are our two operands. We're just looking at addition. And for now, we are assuming that they are positive numbers. We will, after we build an addition, we will come back and look at subtraction and and negative numbers. But we would expect then, when we're doing this addition, you'd start with the A1 and B1. You get a sum one, and then you get a carry one. And then you would add those A2, B2, and the carry one together, and you get a sum two and a carry two. And then you'd add A3, B3, and the previous carryover, and you would get sum three and carry three. And this process would repeat, and then the one interesting is the very last addition. We take the carry 8, and if it exists or not, we bring it down. So this is the, the addition we have, and all we need to do is chain eight of these full adders together. So I will start by drawing that out. And this is not going to be a pretty drawing because I don't have good handwriting. So I am just going to go silent for a minute as I draw this out, because I find that the more I try talk while drawing, the more errors I make.

So, we start with a full adder, and we're going to feed in A1 and B1. And then we actually feed in this hard-coded zero for the carry-in. And then we will take another full adder. And I probably drew that a little too close together. And from the output of this one, we get, I'm going to bring this down here just so it's easier to read. We get the sum one, and then the carry one is going to come over here. And for this one, we will feed in A2 and B2. And this is still a full adder. And we get sum two coming out, and then we're gonna have the out, the carryover feed into the next full adder. So then we have another full adder, and we're going to feed into here A3 and B3, and don't forget about the carry-out that's going to come in. And then from here, we get sum three. And I'm going to move this over before I run out of room. And then what we're going to do is we're going to have another full adder. And that's going to take in A4 and B4 and the carry-out from the previous adder. And then we're going to have the sum four and the carry four. Then we have another full adder. We feed into this one A5 and B5. And then we also feed in the carry-out from the previous full adder. And we now get sum five and the next carry-out. And then we will have another full adder. I know this is getting repetitive, and that's because it, it is. We've designed this so that we don't have to build out this massive circuit that handles every possible value of the two combinations of 8-bit inputs. We've built this something simple circuit, this full adder, that lets us reuse everything. And once again, we feed in A6 and B6. And then we also take the carryover from the last one. And from here, we output S6. And we are getting so close. We have a full adder. We get an A7 and B7 and the carryover from this last one, and we get S7. And now we have our last full adder, where we take in A8 and B8. We get this S8. And then we're also going to get this carryover from eight. And the last thing we need to do is make sure that we chain this carry-in. Cool. And I'm not even actually allowed to zoom out that far on my, my iPad without it complaining. So I'm going to hold it here, and let's look at what we have. We've now built a circuit where we can put in any two 8-digit values into our input lines, and we'd be able to output their sum. And I'm not going to work through an example because I'd probably take me just as long as the entire video up till now to look at each of the logic gates for each of these full adders. But you should be able to convince yourself this is true. And this is something that's really novel. We've built something simple, and we've chained it together to build something more complicated. And this is a fundamental principle of computer science. It's called abstraction. We've built the circuit that's a full adder, and we then we've abstracted away by just drawing it as a rectangle, and then we're building something on top of it. And that abstraction actually lets us, lets us add, uh, 8-bit numbers. So we've, we've taken these logic gates, which on their own are pretty trivial, and have now forced them in, arranged them, is probably a better word, should I say, we've arranged them in such a way that the logic gates do something useful to us. And you may be wondering, this is, this is cool and all, but how does this actually happen in the real world? Well, I mentioned this earlier, but, uh, all of these lines I'm drawing, you can actually think of them as wires. And the fundamental property you need to understand of wires is that they conduct very fast. So if I have a long wire, assume there's no electricity on it. If I put electricity on it on this end, then we will say almost instantly, this is a big asterisk, the electricity will appear on this side, because wires conduct electricity. And we're saying almost, because nothing in this world is immediate. And there actually is a little bit of delay between when we put electricity on a wire and when it's received on the other end, you know, cuz electrons actually have to move across the wire. So what you can actually believe in, and, and kind of use to understand this, is that all the lines I've drawn in these above diagrams and up until now are physical wires. And this is not an exaggeration. This is, this is the truth. And if I, I also said that we can build these logic gates physically. You can buy these little chips that have them built in. And so one such chip has, it looks like this. And it has many inputs and many outputs. But I could then put electricity on this line, and this line, this line. And I, by electricity, I mean I'd either put electricity or not put electricity. This is a high level. Again, there's a little bit different in the, in the world of physics, but this is how we will understand it, and how I think it's all you need to understand it as. And if I put electricity on the wire, we say that it's a one. There is a truthful value on the wire, a one. And if there's no electricity, we interpret that value to be a zero. So then this chip that, that does exist internally, does something. It somehow manipulates the electricity in the real world to function like a logic gate to this output. And I have this chip. And so if I genuinely put electricity on this wire and didn't put electricity on this wire, then there would be no electricity on this output wire. And then if I did put electricity on both the input wires, then there would be electricity on the output wire. And we're not going to study how this works in the real world. We're not going to study how you can build these logic gates. But it is, it is really possible. And it's, it turns out it's not too difficult to actually build them. And there's a lot of resources online which, uh, I'd be happy to link if, if someone requests. But what we do want to understand for the sake of this video is that when I'm drawing these lines, they're actually wires. I'm, I'm drawing something out that could really exist in the real world. And these lines are wires. And when I say put a one or put a zero on a, on on a line or comes in or out of a logic gate, I'm really saying we either have electricity or don't have electricity. But, but thinking about it at the level of ones and zeros is certainly easier than thinking about it at the level of electricity or no electricity. Electrons or no electrons. So I'm going to stick to this understanding where I say zeros and ones. But really, you should understand that this is actually something that could exist in the real world, and, uh, something we'll talk about more, more later on down the line.

Okay, so we've now built an 8-bit adder. We built an 8-bit adder, but there's an issue here, and I, I've mentioned it a few times. How does subtraction work? And it may seem to you like we will need to destroy what we have and rebuild the entire computer or the entire adding logic circuit. But it turns out another really interesting takeaway, uh, at least what I would call interesting, is that we are actually 95% of the way there with what we have up top to being able to do subtraction. And the reason is, is remember what we said earlier. We said that if we wanted to do A minus B, it is really the equivalent of doing A plus negative B. And so we know this circuit can do A plus negative B. But the issue is we have B feeding being fed in as all of our inputs. We don't have negative B. And how then, if we have all these B inputs, can we actually make them negative B? So what I'm going to do here is pause this video and redraw this circuit in a slightly more optimal and more condensed way, and at least in a way that I can, I can show everything on my screen at once, and then we will, I will, uh, cut back, and we can pick up and answer this question.

Okay, so I have drawn this in, and let me go ahead [clears throat] and erase these bars on the side. And let's do a little recap of what I have here. And you've also noticed that for about the first time in this video, I've decided to use something besides the color white. So you're welcome. And basically, I wanted to color code things because we have a lot going on here. And I'd also, before I even start to explain this, would like to appreciate, or hope that you can appreciate, how much less painful this is now that we've abstracted these logic gates out of the way. And it's still pretty messy. So we, we can do more eventually. We'll abstract this entire thing. But, um, as we have it right now, there's, this is, this is fairly reasonable to look at. And hopefully with the color coding and the explanation I'll give in the next few minutes, we can make sense of this. [snorts]

So, what I have up top are our eight A inputs and our eight B inputs. And I'm drawing these little circles because, uh, you'll, you'll see this notation if you ever end up watching some other videos where, uh, this, this represents an input almost. And we can either put in a zero or a one to that input. And it's just a notation. And I personally think it's a reasonable notation. And if we were to do this in the real world, then this circle would probably just be some source of electricity or not. And, you know, we, we'd connect electricity there and go through that wire into the corresponding full adder. [snorts] But I have all the A inputs highlighted in red and or orange, if, if that is orange to you. And I'm actually not sure what it is to me. I, I'll stick with the orange. So I have all the orange connected to all the A's, and those go into the A lines of the full adder. And it doesn't really matter if we commute A or B for the full adder. It doesn't really make a difference because A plus B is the same as B plus A. But more interestingly, I have, or equally interesting, I guess there's not really anything more remarkable about it. I have all the B's in blue going into the B inputs of each of these eight full adders. And then I have in gray here the carry-out from each outer adder going into the carry-in of the next adder. And the one exception to that is the very last carry-out from the very last full adder. And that comes down here. And so, uh, the greens are the sum bits of each of the full adders. And sorry, I don't know if I was just saying half adder. I meant to be saying full adder. If I was, I apologize. And the, we know that the carry-out from the last full adder is special because it, it is not just carry-out, but it's part of the, the output of our sum. Whereas all the other previous carry-outs, we, we need them to do the computation, but we don't really care what they are. We just care what the result is. And that last carry-out is, is technically part of the result. And the only other interesting thing is this, this over here where I have this carry into the very first full adder. And we said that's just going to be a zero. So I kind of written this zero in quotations. And, uh, I, I've, I've given it some special attention. That's because we're going to see that it, it may not actually always be the case that we want it to be zero. And I also wrote S9 in quotes down here because it's, it's really equal to the carry-out of the eighth full adder. So we could say carry 8, but I wanted to make it apparent now that, you know, even though this is the carry-out when we use it, it actually does become part of the product, the result of the sum. And so I think it, it makes sense to treat it like the rest of the result bits. But I'll leave it in quotations from this diagram for now so you can understand that it is, it is a little bit different than the rest, and where it comes from. But when it comes to interpreting the output, it's the same. So now you can see we have this circuit where we could put in our A values and then our B values, and then we'd be able to read the output right here. And you could understand all the logic gates if you really wanted to. You could take this yourself and draw out all the logic gates, but that's, that's not necessary for what we have going on right here.

Now, what we really said that we wanted to do was figure out how to do this subtraction with our circuit that we have here. And we know that this circuit can do A plus B. And the issue is we want to do A minus B. And how could we do that? Well, I, I invoked the rule that we learned at the start of this video, which was A minus B is equal to A plus negative B. So, what we really want to be able to do here is take the inputs. We'd like to have the same circuit. We'd like to be able to use the same circuit for addition and subtraction and have a way of telling it when we're adding and when we're subtracting. And when we're subtracting, we don't want to feed the B's. We want to put our, our B input up here, but we don't want these wires just to feed directly into these gates, cuz we want negative B to feed into each of these adders. And so, let's think about how we can accomplish that. And I'm going to write down what we learned earlier. Given B, or given A, or B, or C, any variable, to get negative B, what do we do? We do, we invert every bit in B. So invert the bits [snorts] bit meaning just a digit position in B. And more formally put, let ones become zeros and let zeros become one. And once we do that, there's one other thing we have to do. If you remember, that's what we have to add one to the result. So add one to the result. And that's, that's decimal one, or binary one. They're equivalent. Whatever one you want to conceptualize. Um, and so if we had, if we had this number 1 0 1 1, and we wanted to negate it, then we do 0 1 0 0. So that's our step one. Then we add one to that for step two. So we do 0 1 0 0 plus 0 0 1. And we're left with this result right here. And you might be wondering something very valid, and that's I said up until this point, we, we've been building these full adders that only work on positive numbers. And that's true, but it actually works out with negative numbers as well. And this is true because I very earlier in the video, I showed you how to do addition and subtraction in binary. And we learned that addition for negative numbers is the same as positive numbers for two's complement representation. And subtraction also works out as long as we can just negate the number. So this circuit, we've only been using it with positive numbers, but it turns out we can use it to add negative numbers as well. And >> so now we're going to learn how we can, now that I've kind of, I kind of shaken that up a little bit because I've been ignoring all these negative numbers, but it is the case that this works with that, that it does work with negative numbers. You could actually plug in an example, maybe maybe not on the 8-bit one, but on our, our two-bit example, our two-bit adder when we just had two full adders chained together, and, and see that it actually does work out. And what we're interested in though, back to the topic, is how can we do subtraction? And so we have B, and we want to get negative B. So what we really saw is we could take all of the bits from B for step one and just flip them. And how do we do that here? And what we can recall is that we actually have a logic gate that does exactly

This. And it's our good old inverter. The inverter looks like this. And if you feed it in a zero, you're going to get a one. And if you feed it in a one, you're going to get a zero. And oops, let me erase that. This is exactly what we'd like.

So to accomplish the first step, what we can really do is is have our inputs of B and just feed each of them through an inverter whenever we want to subtract. That's the issue. We we want to be able to distinguish when we're adding and subtracting. But let's just assume that we're just going to use this for subtracting. So we'd we'd end up inverting all of these. And so I guess I'll just draw an arrow and I do some uh some sort of demarcation that we'd invert. And that handles the first step.

And then the second step is adding a one to the result. And now let's think about this because this is this is a little bit weirder. And how could we do this with the paradigm that we have up here? Uh this is a good good challenge question. And it turns out to add one, we could just feed in a carry-in of one to the very first addition because we know that when we have uh for some digit position when we're doing addition, if we have a to the x and then b to the x position, then we also take in a carry in at the x position and we output a sum at the x position and a carry out at the x position. And this carry in effectively just adds another value to our step. And what we've been saying so far, if we come back up here, is that when we're doing these 8bit addition, then we actually are sure that we're never going to have a carry in the first time because we have nothing else to carry in from. But if we actually just set a carry-in to be one, then we're effectively adding one to our overall result. And so this actually works out perfectly. And so you might be wondering, well, this this adds one to our result, but we're trying to just add one to B. But doing those are synonymous. If I do um if I do a plus a + b, so if I have all these a's and then I have all these b's, but I want to do neg a minus b, then I first off, I invert all of these. And I'm just using this bar up top. Uh this this this notation of of this bar on top of B just means the opposite of B. Um and if we just throw a one up here, then this is the same thing as doing and now this becomes addition. A a a plus [snorts] and then we could have done uh bb the negated version plus a one. So if we did that sum and then this outer sum, then it's the same as just just doing it all at once because a plus we're effectively saying here that a + b + 1 is just the same thing as a + b + 1, which could just be however order you want to permute it because addition has this this commutive property you learned about when you when you were way younger. And this is a really powerful result. This lets us mean that when we want to do subtraction, we could just set this carry in which we know is going to be a zero for addition to be a one and it adds one to our result. And so we found a way effectively using our circuit of full adders that we originally designed for addition to be able to do subtraction. And when we want to do subtraction, we're going to do instead of a minus b, we're going to do a plus negative b. And we have b's as the input over here. And to make it negative b, we're going to take the two-step process. The first of which is inverting all of b's bits from ones to zeros or zeros to one. And the second step is adding a one to the result. And we can do both of that with the circuit we already have minus a few additions of inverters.

So what we're going to go ahead and do now is there's one final step and that's that we need to distinguish when we're adding or subtracting because when we're adding we don't want we don't want these values to be inverted and when we are adding we also want this carry-in to be a zero but when we're subtracting we want the carry-in to be a one and when we're subtracting we want all of B's bits to be inverted. So, how can we actually do that? And what we're going to do is add another input to our circuit. And that's just going to be the addition subtraction flag. So, I'll make this a circle for consistency. And I'll just write this is a slash s. And what I'll say is that if if this is zero, so if zero, then addition, and if one, then we'll do subtraction. That's just how we're designing this. And then we'll be sure for the rest of this of this uh to make sure that we adhere to that consistently. And then what we want to do is how do we deal with well this this first part's easy for the inverting the adding the one. It's easy. It's just the value of this because if we are adding then we want no carry into the first full adder. And if we're subtracting, we want to carry into the first full adder so that we have the effect of one, the effective addition of one that we needed for the binary conversion. But this this inverting part is a little difficult. If we have this line and we have a value, let's just look at B1, then how can we use both of those to get the right B1 that should go into the gate or the right, I guess, uh, modified B1 or not that should go into the gate. And so what we really have is if as is set so if as equals 1 then let b then we want to invert so we should invert b1 and if as is zero meaning we want to add then we leave b1 alone and how can we do this? Well, a a simple simple gate. We can do one gate and that's the exclusive orgate. And let's see what that looks like. So if we feed in B1 here and then this AS line, then let's look at happens for each of the input cases. So if as is one, then we want to invert B1. So if B1 is zero, then we would we would hope to get a one out and one exclusive or zero is one. So that is correct. And similarly, if B1 is is is one, we'd hope to get a zero out. And one exclusive or one is a zero. So So this works. And then if as is zero, we would want B1 to to come out exactly as it is. So if as is zero, if B1 is zero, then zero exclusive or zero is zero. So that flowed through. And if it's one, then we know one exclusive or zero is one. And so that is exactly how this behaves. And if you have a little bit of trouble conceptualizing that, go back earlier to when we looked at the truth table for the exclusive orgate or you can just Google it now. But this is just a property of the gate and it it works out very conveniently that we can use it for this this task that we have right here. And then it turns out this is uh we were looking just at B1, but we can do this for each of the B's. And that's exactly what we'll do. We will have an exclusive or gate for each of these B's and we will exclusive or the corresponding B with the same AS line that we have up here.

So I for the sake of drawing am going to pause and update this diagram to have that in there. Okay. So I've updated the diagram now and I was running out of color. So I have this lightish purple and basically all that changed in the past millisecond is I have exclusive ored each of the B gates with the value from this as line this addition subtraction line before feeding it into the B input of the full adders. And so what this means now is that if we want to add, we load in our values to A, load in our values to B, and then we can look and get the result on the S lines down below. And if we would like to subtract, we do the same thing. We put in the A, we put in the B, and then we set this AS line to be one. So whenever this as line is zero, it's just going to add this circuit is just going to add whatever is on the input lines. Even if we don't have any meaningful value, it's it's a circuit. The logic gates are going to do what they do. And we're going to get some output that we can read on these S lines. And if we set this S line, this AS line to one, then it's going to subtract whatever values happen to be on the A line and the B line and come into this S line as the output. And so this is the extent of difficulty we're going to need for this video. And computers can do uh multiplication and division, but it's a bit more tedious and involved of a process. And I don't think there's as much not to say there's not benefit, but I think this suffices for understanding the rest of the fundamental concepts of computing. So there is no plan for me to show how subtraction or multiplication division work but there is plenty of resources online that you can feel free to look up if you are curious about it. It is uh interesting because we then have to without going into too much detail you have to update how you represent numbers. For instance, we can only represent whole numbers. But if I divided seven by two, the output's 3.5. But we have no way in binary b up till now what I've taught you of representing this.5. And so you kind of have to go back and and revisit your representation of numbers. But we're going to stick with this two's complement.

And so now we're back and we have this we have this circuit that can add. But there's a little bit of an issue. And it I think I've kind of made it not super clear until this point until I was working through, but that is these are logic gates. And so they're always just going to operate based on whatever the inputs are. So if we don't really have any meaningful values on these A lines or B lines, there's still going to be some value in the S line. But that what that also means is if we did want to add two numbers and we put them in the A lines and B lines, then the output's going to correctly come out on these S lines down below, but as soon as we change any of these inputs, the output may or may not change. And that's that's that's actually problematic. Uh we'd like to be able to to save the result. And let's say I'd like to to add two numbers, put them I put them on the A lines and B lines and I get the result. And then let's say I want to take that result and and add it to something else. Then right now there's not really a clear way of me doing that. And that's kind of as we're going to get into the more uh different components of computers and how we can actually make this this this adder and subtractor do meaningful work rather than us having to manually put electricity or at our level put zeros and ones onto each of these input lines. And what we've built right here is 95. Again, we're not fully done. We're actually going to revisit this one more time, but it's not going to be to add anything too more complicated. But what we've built right here is called the ALU. Stands for the arithmetic logic unit. And every computer has one of these. Uh the computer you're watching this on has one. And it's responsible for doing doing the arithmetic. And I mentioned this earlier, but computers are effectively glorified calculators. So, this is actually probably the uh heart of most modern computers. And obviously, your computers are implemented in ways that make these run incredibly fast and uh can do a lot more than what I've shown uh more than just the addition of subtraction. But this is just to illustrate the concept. And what we'd like to do, as I' I've kind of hinted now, is be able to take the result of an addition or subtraction we do on this circuit and save it. But we know with these logic gates that the moment we change one of their inputs, the output may or may not change depending on what the gate is. But in general, it's it's safe to assume that once you change the input to a logic gate or a circuit, if you change any of the inputs, it's not necessarily going to be the case that the output stays the same. So, if I have these A lines set to some value and I have these B lines set to some value, I would need to in the real world wait a small amount of time for these logic gates to do their work and settle. And then that's something we'll talk about more later. But then once we we give it some time to settle and it do all the electricity flows through and everything, we we'd like to be able to take this output and save it. And this is a what I mentioned earlier in the video at the very start. This is going to be the second hardest concept we taught in the video. The first most difficult I in my opinion was learning binary which you made it past and this is the fullest you'll learn binary. But the second concept is how can we save numbers with logic gates. And so I'm going to scroll down because this is going to be a new segment of the video.

So everything we've looked at so far had this property that I talked about earlier called determinism determinism. And what this meant is that the output of a circuit dependent strictly on the input values. And this is not really that complicated or it probably sounds a little bit obvious to you because obviously these outputs just determine on the inputs because they all chain into each other. But let me give you a circuit that actually breaks that principle. And it's something we haven't seen before. But uh what happens if I take this simple orgate? So this is the orgate. And I have some input. Let's just call this X. And let's take the output of this orgate and actually feed it back in as the other input. And this is really weird. We haven't seen this before. We've seen the output of logic gates go into the input of other logic gates, but we haven't seen the output of a logic gate come back into itself. And this is going to break this idea of determinism because let's assume that when I turn this on, I have a zero on this line. And then let's assume that there's a zero coming out. So I have zeros all around. So I have if I make this input output, if I make a truth table, actually that's what we'd like to do. So let's call this this input X and this output Y. Then I've shown right here that we could have a zero for X and that we have a one for Y. But now let's look at what happens if we set this X to be a one. So if I set X to be a one, then we have the inputs 0 and one feeding into an O orgate. And an O orgate turns on as long as either of the inputs is one. So then the output of this orgate becomes a one and something else happens at the same exact time is this output becomes a one but it's also the input to this orgate which means it's this input is now effectively a one as well and what this means is that this this orgate is now forever going to output a one because we have it outputting a one now which means it's inputting a one on this top line and that means that it's guaranteed to be getting in a one forever. And what I mean by that is you convince yourself this is true by changing this input x back to zero. And if I change it back to zero, then notice that the two inputs are a zero and a one, which still ores to one. And this might take a little bit to wrap your head around because it it is fairly confusing and I I struggle with this when I learn the concept. And it's not very intuitive to take the output of a gate and feed it back into a gate. But it turns out that when we do that, we have some really powerful properties that we can achieve. And so if you can kind of understand that what's happening right now, uh let me prove to you that this is unlike anything we've seen. If that's not already clear, because now we have a zero uh a sorry, this this is correctly incorrectly written. When we powered this on, we had a zero going into x and we had a zero coming out. But now we have a zero and then we so we started with zero going in and zero coming out and then we made it a one going in and we had a one coming out and now we've set x back to zero and the output is still a one. And you may notice that these [snorts] first and third entries in this truth table contradict each other. And what I said about determinism earlier is that a circuit is deterministic if the outputs depend strictly on the inputs. And clearly this is not the case because we have this output one and it happens sometimes when x is one and sometimes when x is zero. So this output one isn't depending just on whatever the input x is at the time. There's clearly something else going on. And the difference here is that the output depends on not just the input but also previous values that were emitted by the circuit. And so this is what we call a sequential circuit. This is sequential logic. Sequential logic does not have this property of determinism that made things work out well. And as we've seen, this isn't an invalid circuit. We've done something valid here. We've just taken the output and feeding it back into one of the inputs. But a truth table doesn't actually work. And we're going to have these things called timing diagrams that that that better illustrate this property.

So let's try create a timing diagram to explain what we saw here. So I'm going to erase these again. So this timing diagram is literally going to be a graph with time is the x axis and then we'll say a uh we we'll have separate lines for the x and y. So oops did not mean to erase that x and y. And we assume that they both start off as zero. So we'll we'll we'll let this be uh the the zeros line and then we'll let the one for y be up here and we'll do the same thing for x. And so x and y are different but they both progress in time together. So we want to see how x and y change as we move forward in time. So we started off with zero and zero and then I eventually at some point changed this x to be a one and at the same exact time this y became a one. So I set x to be a one and then y became a one and then we just left it like that for a little bit. And you may be wondering uh I said earlier that these logic gates have a little bit of delay in the real world. And so if I set X to be one, there should be a little bit of delay before Y becomes one. And that's that's the truth. But we we won't worry about that delay for this part. Uh we don't want to over complicate too much. So let's just assume that this logic gate works instantaneously. As soon as one of the input changes, the output immediately reflects what the correct value of that logic gate should be. So then now we have one and one. But the difference is that I noticed that when we brought this x back down to zero that y stayed as a one and then time continued and they both just stayed where they were at. And it turns out no matter how many times we bring this up or down this y is just going to stay at one. And so this is what we call a timing diagram. This right here shows the state of a sequential circuit as we pass through time. And we saw the issue with the truth table is that a truth table does not complete the full picture for a non-deterministic circuit. But a tying diagram does let us see everything that's happening. And so this is something that we will see uh increasingly in the next segment of the video.

But what we'd like to now do is I'd like to show you how you can build a sequential circuit that actually lets you store a value. So we talked about this this 8 bit adder we have here and that we wanted to be able to store the outputs that are are coming out onto these output lines and we're going to dumb this down. We we didn't build this this 8 bit adder all at once. We started with a one bit adder and then scaled up. So we're gonna do the same thing. We're going to try to build a circuit that is sequential that can save one bit of data. And we'd like to design this circuit so that we can choose when we we save the value um and update its value afterwards. And so what we're actually going to do is I'm going to scroll all the way back up to one of the first things I showed you, and that was this selector gate right here. And I'm going to copy this down below and this will go right here. And this selector circuit is deterministic. The output depended strictly on the inputs. And so uh if you happen to not see the earlier part of the video, then I'll just go ahead and quickly summarize. Our selector circuit takes two inputs A and B and the output of that circuit will be the A input if C is zero I.e. If C is zero, then we let whatever A is flow through. And if C is one, then we let whatever B is flow through. And I originally showed you this this circuit earlier in the video to show you uh a motivation as to how you could build more interesting circuits by chaining logic gates together. And this was the first example I showed. But it turns out we can uh we can we can kind of build something very interesting by by making this selector non-deterministic. And so let's see just how we can do that. And what we saw when we did this orgate earlier, we started with the ordinary orgate which looks like this. And we made it sequential by doing something like this where we took the output and wired it back in. And then we had our one input and this was simultaneously this y line was an output and it is an input over here. So we're going to be able to do something very similar with this selector. So I'll keep the original selector up there for reference. And then I will bring this one down. And all I'm gonna do is with this Y, I'm going to get rid of our input A here and feed it back in. And I don't know why I drew that so far back. So I'll redraw that. And now let's see what happens. So our inputs are kind of weird. We have this this C and B. Uh it doesn't really matter what they're called. Well, why don't we just uh make this easier and rename this A because we no longer have an A input. And so we have a A input and a C input. And I'll keep the C as C because later it's going to stand for the word clock, but we don't really know what that is yet or why. So I'll I'll leave that there just so when it is introduced later, it's not as confusing to understand. Uh but for now, let's just think of it as the control line because that's kind of what we saw in the selector. The C is what controls which the inputs goes through. And then this Y stays the same. So let's see what happens. Let's suppose we start our circuit and C is a zero. Then we know that when C is a zero, it lets the value up top flow through. And let's also assume when we start the circuit, everything is a zero. So this Y is also a zero. So we have a Y coming out and then we have a Y over here, which means and you know the Y flows through. So the if we uh even try to change this a to a one let's say then uh the other output the other input to this and gates a zero. So this this output of this and gate is always going to be z is zero regardless of what a is and then we have the zero ored with the zero and so we're always going to output a zero. But then let's suppose we have our zero here. So we have our zero on y still. And let's let's go back to zero A. And now let's suppose we flip C from 0 to one. And now what this means is that whatever's on A's value should flow through. So [snorts] we have this we have this zero going through and it's just going to propagate out. And it's also we already had a zero. So it's going to propagate in. And that's the same thing as before. But things get a little bit interesting when we actually take this a and make it a one. And that's not the only thing we need to make this interesting cuz we know when we make a a one then this is going to be a one which means this is automatically going to be a one and this is the same one as above. So all that's really changed right now is is is nothing. We've seen that when C was started off as zero, then we actually weren't able to change the output at all because it was just the the input the output was flowing through in a circular fashion. But now in C's one, we let this a flow through and it kind of controls this entire circuit because it flows through and it's flowing back around here. But let's look at what happens the moment we go from a uh from c being one to zero. And this is where things get a little bit tricky to rationalize. But what we see here is that we start off we have a one coming out here which is a one up here. And I'm just actually going to erase that cuz it's the same one. It's the same wire. And we have C being one. And the moment we go from C being one to zero, then what happens is that this becomes a zero and this becomes a one. And we know that the output of 0 and one is zero here and the output of one and one is one here. And so we have this one come through and then the output of that orgate is still going to be a one. And this line doesn't change at all. And that's uh a little it may may take a little bit to understand that but nothing crazy has happened. But if we change a to zero then nothing is going to change either because we already know that this and gate is always going to output a zero. And we know that when c is equal to zero the uh whatever value is on this line is going to flow through. So what this pretty much means is we have two observations is when C is zero output doesn't change output doesn't change when C is one. The output follows A. And I'm using follows as synonymous with equals. The output is just going to be whatever A is. And the interesting thing that we saw is that when C goes from 1 to zero, C goes from 1 to zero, then we actually freeze whatever the output is at that exact time. We kind of and the output at that exact time was whatever on was on the value of A. So when C goes from one to zero, we lock in the value of A. we lock in the value of a and it's not going to change the entire whenever c is zero as we already dictated because we set it up here we have a rule that the output doesn't change when c is zero. So when C is one, we have this output following whatever A is. And then the really interesting thing is the moment we go from C being one to zero, we kind of latch in A's value. And this is very interesting because now we can freely change A and the output doesn't change because of our rule up here. So in an interesting way, this is actually storing data because what we have happening is if I wanted to store a value on this line Y, then what you could use, what you could infer from these three rules is that you would need to set the value of C to one to let the output equal whatever A is. Set A to whatever you want it to be. And so then the output currently equals A, which is what you wanted it wanted the value to save. And then you set the C from one to zero and that locks in the value. And so the output is still the exact same thing that you had as a but now you can change A freely and the output is still captured. And this is really useful. And what we've done now is we've we've effectively stored data. And I think this this diagram gets a little bit confusing. So the same way we represented a full adder with a rectangle, let's go ahead and represent the generic selector as so. So we're going to call this selector notation. And we have a b and then uh we can call it c for your your your choice or s for your selector. I'll just call it call it c. And then you have your output y. And all this is saying is this is our original selector before we had the output going back to the input. So that right here represents this. These are the same A, B, and C and Y as before. And so what we've done now, and I think a more intuitive way to represent this is we've taken I don't know why I made that so vertical. We've taken this A output and gotten rid of it. So we just have this B and this clock, this carry, this choice, and our output Y is still going to be an output, but it's also going to serve as an input. And you know the rule selector is that we've seen that we kind of have this above. So when C is zero, the output doesn't change. When C is one, the output's going to follow, and I'm just going to replace this with A. It's going to follow whatever A is. And then the interesting case is when we go from C to one, I've shown you that we actually lock in a value. And we've come to a point in the video, I've been drawing on this screen for about 3 hours that my my regressive handwriting skills are are getting a little too complicated to follow for you. We have these ones and zeros diagrammed all over these these these logic gates, and it's it's not very intuitive what's happening anymore. And we're actually, as we saw earlier with sequential logic, we have to rely a lot more on timing diagrams. So, it is time for me to actually switch over to some computer software and make this a lot easier for you to understand.

So, let's look at this exact same example before, but let's let's migrate it over to computer software. So, I'm going to switch screens here now on this new software. And as you can see, our logic gates are actually drawn somewhat visibly coherent. And I've built the original selector that we've seen. And I'd like to show you that the selector works as we expect. So what we have right here is I'm going to set our our C is zero. So I guess I should first distinguish distinguish that this this dark green represents a zero and this this lighter green represents a one in the software I'm using. The software I'm using is actually called digital. The website that I link below that I wrote with one of my great friends is all of our graphics are built in digital and you can actually follow along. There's instructions there. I won't explain exactly how to do everything I do in digital, but you will see me build out in digital. And for now, all you should need to know, and I'll walk through everything as we go, is that this this light green is a one and this dark green is a zero. So in our first case, we can see that C is a zero. And the rule we said earlier for a regular selector is that if c is equal to zero then y should follow follow whatever a is. And we see this happening. You can kind of see and I think it's easier to visualize now the this this this a just flowing through. And you can see b's value just gets cut off by this and gate because its value is zero. And this is far more intuitive to see on the software once you can recognize the the lighter green being a one and this dark green being a zero. And then we can see that if I if I toggle C, then the output should follow B. And that's exactly what happens. So the output follows B no matter what A is. And we've we've built a a our our selector circuit. And another cool thing the software does is it will let me generate a truth table automatically. So we don't have to do everything by hand. So you can see for this this circuit we have right here that the truth table that I I have drawn out previously in the video is equal to the same truth table that's being shown right here. And I won't switch back to my drawing because it's going to be a pain, but you can go back in the video and see yourself that's true. And then the last thing I showed you before I before I switched to this view was that there's a a notation the to draw a selector. So, and we said it was represented with this right here. So, let's go ahead and see what that looks like. So, I'm going to copy this over and we will see what the output looks like. So I have our A and let me call this A2 so we don't get it confused. Then we have B. I'll call it B2. And then we can also have our C2. And these are the same. This is the same circuit before. And and we're going to have our Y2. And another thing about the circuit is we represent our inputs with these squares. And you can see you saw me previously clicking them. And our outputs are going to be these circles. So now if I if I play this, let's convince ourselves this is true. So C2 is zero. So the whatever we set A, it should flow through and that should happen regardless of what regardless of what B is and we see that happening. And then if I toggle B, then nothing should happen. And that's the case. And then if I flip to C, flip C to one, then we see B flows through. And toggling B lets that value flow through. and toggling A has no effect. And hopefully you that is enough to convince you that these are are are equivalent circuits. And I can actually delete this right here and do the same truth table generation. And if you go back uh less time this time, just a minute, you'll see that these true these two truth tables are the same.

And so now what we want to do is do what I showed earlier where we took the output and chain that to the input. So I'm going to rename this. I'm going to rename everything accordingly. And this A goes away. But let's just call this this B and let's call this C. And let's actually just we said A when I was drawing on the screen. So let's be consistent here. And let's have this output feed into the input. So now if I do this then the point I was trying to make earlier which I think may have been a little hard to visualize without seeing it in this manner is that whenever C is zero the output is not going to change because whenever C is zero we let this top input flow through the output. And then whenever C is one, the output's just going to be whatever the input is, whatever this value A is because a selector behaves such that when the C is equal to one, we let the bottom input flow to the output. And the interesting thing was then when we toggled C from one to zero and what we said is going to happen is that at the moment we toggle C from one to zero, it's going to go from letting this bottom input flow through, it's going to go from letting the bottom input flowing through to letting the top input flow through. And the top input is actually equal to the bottom input whenever C is one because it's all the same circuit as you've been able to see. So what's going to happen is I'm going to toggle this to zero and this value is going to start coming through and this value is a one and it's going to trap this one in this loop right here. We have a little bit of a feedback loop happening and I know this is a little difficult to understand but uh it should be it should be this is what I explained is the other one of two hardest concepts to understand in the video is what I'm showing you right now. But let's see what happens. So we toggled this C from one to zero. And this is what you would expect because the input at that time we toggled C from 1 to zero was a one up here. And so when we actually toggle C back to zero, we just let this one flow through. And now it doesn't matter what we set A to because it's we have this rule that whenever C is zero, we just let this top input flow through. And so we've actually trapped the value in here. And if we wanted to trap a uh a one a zero in here, then what we need to do is have C go from one back to zero. So in order to do that, we have to set C back to one. And then we would set whatever value we want on A. And then to trap it, we'd set C from one back to zero. And the the remarkable thing that's happening here is that we trap the value on A at the exact moment that A C goes from one to zero. And let me show you exactly what I mean. So I am going to add another cool thing this software has is the timing diagram we saw from before and I'm going to bring this back in case I need to use a lot of space. But we start off with C. These are all zeros. Uh we see the two inputs are zeros and the outputs are zero. If I toggle one, if I toggle this A, nothing happens because C is zero. And then when C is one, you can see on this diagram right here that the value of Y is just equal to whatever the value of A is. And then suppose we wanted to lock in a one as the output. I need to have C go from the one it is right now to the zero. And you can see that C goes from one to zero. And now it's at this my claim is that it's at this exact moment that we lock in the value because now whenever I change a c is going to stay at that original value that it was at. And now suppose I wanted to lock a zero in. We said it only happens we can only lock a value in when this C goes from one to zero. So what I need to do is bring C back up to one. And as soon as we do that we can see that the output starts updating. It follows our input A. But to lock it in, I need to bring the C back down to a zero. And now you can see the C, we have this falling clock edge. We have a rising clock edge here and a falling clock edge here. And the falling clock edge is what actually latches in that value. So now I toggle A and nothing changes. So the good news is that if you follow me, you're halfway through the complexity. We're going to turn this up one more notch and then we're going to be done. So the good news is you're halfway. And the bad news is that it gets a little bit more complicated than this. So if you do find yourself confused by this, this is not something that you should let stop you from proceeding. You should check out the website that's linked in the description that I wrote. It's it's meant to illustrate this example a lot more detail. And you should just draw through this and play with it by hand until you're able to rationalize what's happening. Personally, when I learned this, I found this incredibly difficult and was not able to wrap my mind around it for days. It took me multiple sessions of opening up my computer and drawing things through before I finally had this aha moment and everything snapped. So, don't be discouraged if it takes you some time. And once you do feel like you have an understanding of everything I've spoken about this circuit that we have on screen, then you can continue is that this is a something called a positive latch. And what that means is that the output's only ever going to change when C is one. When C is positive, the output's going to change. Interestingly enough, we could actually just negate C and we'd get something called a negative latch. And that's the same behavior is that the output of the Y is only going to change when C is zero. So on the positive latch that we just saw, you lock in a value when the the C line goes from a one to a zero. And on the negative, it's the opposite. You lock in the value when the C goes from a zero to a one. So, let's actually look at what that is. And I have inverter here. And I probably shouldn't have erased this. Let me do this. And now let's look at our timing diagram. So C is zero now. And previously we said that when C is zero, the output's going to follow this in this this top input which is equal to the output. So it's never going to change. But now we see we're toggling A and it is changing. And that's because when you invert this C line to a selector, also known as a multipplexer, it just inverts the behavior. So the original selector let when C is zero, it lets this top input flow through. And when C is one, it lets this bottom input flow through. But now that we've inverted it, it's the opposite. When C is zero, we let this bottom input flow through. And then when it's one, we let this top input flow through. And so if I want to set a value, I need to get it so that we we have the value coming through. And then I want to pick the output to be this one. And we do that by setting C to be one. So to set a value, I have my A. Let's say suppose I want to store a one. Then I need to put this this this C to one. And now we're selecting this top line. And now as much as I toggle A, nothing happens. And then if I set C again, then notice now that the output follows A. And then at the moment where I set C back to one, we start picking this top input again. And so now the output's never going to change. And so this is called a negative latch because it latches onto the value whenever we go from zero to one. So it's it's latching on whenever we have this this input C being one. And it turns out that there is a shortcoming with what I've described here. So this is a very interesting combination of circuits and not that many logic gates that actually enabled us to to persist information. But the issue is that if I go back to this this

original uh positive latch instead of the one we were just looking at, the output is changing whenever C is one. And it works out that if we're trying to store a value, it's fine cuz we know that whenever C is is falling from one back to zero, it it it stores the value in and then it's not going to change. But we'd like that to be true until the next time C falls from one to zero. But that's not the case because as you can see right here, the outputs uh going from 0 to one. And now we have we have this uh we have this this output changing before there's another falling edge. And so it's hard to give full motivation as to why we need this behavior. But it turns out as something that will become more clear as we design more parts of this computer is that if we can have information only change at one specific time, then it gives us more time to actually look at this value. So we know that on our in our current circuit that whenever C falls from one to zero, it's safe to assume that the output is going to be the same. until C goes from 0 to one. And this is this may seem fine. You're saying, "Hey, look, this is a lot of time, but what we'd actually like to do is make this as long as possible." Because I mentioned that these logic gates take time to settle. So, we'd like our output to be able to be used in other parts of our computer for as long as possible before we lose that stored in value. So what we'd like to do and what we're going to do next is update this circuit such that it only the output Y only updates every time C goes from one to zero. And this is going to be very useful because then it means until the next time C falls from 1 to zero that value Y is going to be the last latched on value. And you can see that's not the case here because in between this C going from 1 to zero and the next time C goes from 1 to zero, we have our output Y changing. And so this circuit that we have right here is called a latch. As I've mentioned and we're going to build something called a flipflop which has this desirable property that the output's only going to change when C goes from one to zero. Build this. I'm going to spoil the solution because it is something that would be incredibly difficult to come up with on our own. And once I spoil the solution, we'll go ahead and convince ourselves that it is true. So, the solution is that we're going to take a positive latch, which we have right here, and feed it into a negative latch. And let's go ahead and see what I mean by that. So, I'm going to copy this positive latch we have here, and I'm going bring this over here. And what I'm saying is that I'm going to take the output from this first latch and make that be the out the input into this other latch. do. So I take the output from this latch and I'm going to make it be the input into this latch. And then we we still want the same property where we have one A, one C, and the outputs the Y. So we we have two C's here. So I'm going to get rid of this. And I said we take a positive latch, which we have here, and feed it into a negative latch. And the way just a few minutes ago that I took a positive latch and made it into a negative latch was was by inverting the C line. Because we saw that inverting the C line has this nice consequence that it it flips the behavior of the latch making it a positive to a negative or vice versa. Um, in our in our default case, the software I'm using, it's a positive latch by default, meaning that the input the output follows the input whenever C's value is positive. And if we invert it, then we have the opposite behavior where the output only follows C's input when C is negative, zero. Cool. So let's go ahead and use our timing diagram that we have automatically generated to verify that this property holds that the output Y is only ever going to update at the exact moment C goes from 1 to zero. And the value that it'll latch in at that moment that C goes from 1 to zero is whatever value is on A. So let's say we want to latch in a one here. So C is zero. So I'm going to show the output's not changing even when we toggle A. That's correct. We have our our input toggling, but there's no falling edge. There's no C from one to zero. So we don't change. Now, um I'm going to set C to one. And we see that C the output Y still doesn't change. And this this is different than what we saw before. But we saw before the output y would have changed here. But now as I keep toggling a nothing is going to change because we are waiting for this falling edge of c to happen. So let's actually do that. The moment I toggle c from one to zero we would expect this y to latch in the value finally. And that's exactly what we see. And now I toggle a and nothing happens. And to to do the cycle one more time, let's we've shown ourselves once that this this y value only updates when C falls. It has a falling edge. Let's do that one more time. Let's get back to that point and say I want to replace it with a zero now. So I bring C back up and I can show you that toggling A has no effect. And then I set A to what I want it to be. And now the moment that C goes from one to zero, we should be able to hope that this Y value locks in the zero. And that's exactly what happens. And so this is the exact circuit that we call a flip-flop. So let's try give a more reasonable and intuitive explanation as to why this behavior happens. And this is something that you could derive on your own just by pausing this video and playing around and trying to offer up and justify the behavior of the logic gates that you just saw. But I'll go ahead and spoil that out for those of you who don't want to rationalize on your own like myself would have not wanted to. So what we have here when we start this is C is zero. So whenever C is zero, the output here is not going to change because we're locking in this top value. So in order for us to get a value from A to Y, we know that we have to get A onto this line at some point or else it can't even make it over here. So the only way to get A onto the line is to toggle this C positively. And now we can have A getting onto this line over here. But then the issue is that we also have to we want to get A over here. And because this is a negated clock, the only way we can get a to come over here is if we we get a zero onto this line because then a one would come onto this line and let this value through. And the only way we can then do that is we now have the value on this intermediate wire that connects the two. And it's the exact moment that I toggle C that this value gets trapped in this wire right here. Because when I toggle C, then this original latch that we're so comfortable with now, the output of it is just going to be this top line, which is a one. So C goes down and then this one is going to be locked on here even if I toggle A. So if I do that, I toggle C down. Then notice how me toggling A has no effect on this middle line. This value is is locked into this intermediate wire. And the last thing is that at that same time that we had C going from this one letting this value through to a zero, we also had something interesting happening over here because we we trap the one on this line. But then having this clock become zero means that this line becomes one and that we actually let this bottom input through. So now that in simultaneously what happens is we trapped the value of a on this intermediate wire and we now let our gate output what that intermediate wire is. And I know that probably sounds fuzzy. So, so take the time to justify this on your own, but that's the high level of what's happening here. And I'm again not going to spend too much time dwelling on this because the article that I wrote, which is linked in the description, goes through a lot more. So, I will say that you are 95% of the way done with learning the second hardest concept in this video. There's one final thing we need to do. And so recall that I taught you what a latch is and it was a positive latch. And then I showed you that inverting the clock makes it a negative latch. So what we've actually built here is not a flip-flop, but it's a negative flip-flop because the value is only ever locked in on the falling edge. When C becomes negative, i.e. it goes from one to zero uh a more negative value then the value is latched in. And so this is incredibly useful. But what if we wanted to have the opposite behavior where we wanted the value to get latched in when C goes from 0 to one? It turns out that we just negate our order of operations. So right now we have a positive latch being fed into a negative latch. If we just have a negative latch being fed into a positive latch, then the output is that our our our intuition remains the same except the output y only ever changes on a rising edge when C is becoming positive. So let me go ahead and update this to show that. So I get rid of this negator. So now we have regular C coming into this selector. So, this is a positive latch, but we need to make this one negative. And so, I'm going to do that by bringing this down here. And I'm going to add a negator. Let me rotate this like so. And now you can see that this this first this first latch is inverted meaning meaning it's a negative latch and then this one's the positive latch. So now what happens is that the value of C only ever changes on the rising clock edge. This is because when C is zero we have this value on the intermediate wire. We have this A coming to the intermediate wire. And the exact moment that we toggle C from a zero to a one, then this becomes a zero over here. So we trap in this current value of A in this feedback loop up top. So we're trapped in the value of a onto this line. And at the same time, this becomes a one. So instead of selecting the feedback loop to output, we select the value of this intermediate line to output, which is the value of a. And so we'd expect that when I toggle this from zero to one that the y becomes a one. That's exactly what happens. And now when I toggle this, the output is not going to change because we've locked in the original value of a onto this wire. And it's not going to change because of this this latch right here. Cool. So this is something very powerful. And I'll prove it one more time that the output only changes when C hits a rising edge. And this right here is incredibly powerful. A latch did let us store values, but this flip-flop is going to let us store values in in a in a way that modern computers actually do do things. And it's very important for us that we only update the value that we're storing on a specific clock edge, either the rising one or falling one. because that maximizes the amount of time that the output is stable that this this value is going to be just whatever we intend it to be versus we saw in a latch that half the time whenever depending on which type of latch you're looking at but for either when C is zero or C is one depending on the type of latch the output is just going to follow whatever the input is and that's not as useful to us because we would we would like to persist the value Y for as long as possible. So, now that we've we've seen how to build this flip-flop, let's actually put it to use. So, in the previous section of this video, we built an ALU. And our motivation for even doing any of what I was talking about is that we'd like to be able to save the value of the output of our of our adder. So, if I if I add two values, I'd like to be able to save them. And what we have right here is a circuit that lets us save one value. But what happens if we want a circuit that lets us save two values? And it's pretty easy. All we have to do is just have two flip-flops. And what that means is that if we have a value A1 and A2 we want to persist, then we could feed A1 into the first flip-flop, A2 into the second flip-flop, and then feed the same C control line into both of those. And then at the exact moment we go from a r a rising clock edge, then we latch in both of those values. And the two outputs are Y1 and Y2 effectively save the value of the ALU. And before I want to move on, I wanted to add this in and that is a little bit of notation. So we saw when we built our full adders that it was pretty difficult to conceptualize what was happening. We had so many of them. So we abstracted away as a little rectangle. And then not too long ago, I showed you how to abstract away the selector that we built with this trapezoid shape. And it turns out because this flip-flop we've built is so common, it's called a D flip-flop. Actually, there's there's different variants of flip-flops, but the one we'll use for for our computer, we only need D flip-flops. And we can abstract it away with this rectangle. And what we can see is that takes in a D, which stands for data because that's the data that we're going to be saving. takes in a C, which is this clock signal. And we've we've I I've kind of beat around the bush here, but we'll see as soon as we finish the next section why what this clock exactly is and what it's going to do. And then we get two outputs on the right side. Uh it's called Q and not Q. So, traditionally, if you do decide to research into flip-flops more or even latches, you'll find that Q is the common symbol to denote the uh stored value. And and in this software I'm using, we get Q and not Q because in some certain cases it could be useful to have the inverted value. But what I really want to show is that these two are equivalent. So we know that the value should only update when C goes from 0 to one. So if I want to lock in a one, what I would need to do is is put in a one on my input line. And then the exact moment that C goes from 0 to one, we should see the one co the the value of a get locked in over here. And that's what we see with this circuit. We already we already saw that. And to prove that these are similar or actually identical, we'll do the same. And we see the same behavior here. And then similarly, we know that if we toggle a while uh at any other time, the data on the output line's not going to change. So if I wanted to write a zero, I would need to let the clock go back down to zero and then the clock put the clock from 0 to one. So I do that and then this has the same exact behavior. So, this this right here will be used to represent a flip-flop and it'll make our our analysis easier and it'll save me time when I'm building these circuits having to draw these selectors out every single time. So, you can kind of see this already makes it easier than drawing this and these are already easier than drawing all the logic gates. So, it's really nice to have these layers of abstraction. So now what I'd like to do is we talked about we wanted to save the value that our adder can have. And the issue is I I drew my adder on on my uh iPad, but we don't have an adder built here. So I'm going to stop this and we're actually going to build an adder. Uh we're going to build exactly what we had before and then proceed from there. And if I come down to this arithmetic section, you can see that there is a circuit called an adder. And this should look very familiar. You see there's an A and a B. And then the CI is the carry in we're very familiar with. And then the output we get is a S for the sum bit and a CO for the carry out bit. And what I'm going to go ahead and do is I'm going to pause the video and then build our full arithmetic logic unit and then we will we will come back and and go from there. Okay, so I've cut back and I know this looks like a lot, but this is exactly what we had earlier. We have our series of A inputs and they get wired into each of the A inputs of the full adders. We have eight A's, eight B's, eight full adders and eight outputs. We have all of the B's and we have them exclusive or with our add subtract flag. And then we also have that add subtract flag going into the first carry-in of the rightmost full ladder. And before we proceed to add um our flip-flops to this, let's let's make sure this works. So this is two and this is two. And we expect that 2 + 2 is four and this is four in binary. And if we just have 0 over here plus two, we just get two. That makes sense. or 0 + 1. And if we had something like 3 + 1, we would expect 1 2 4. And we can verify that subtraction still works. Let's suppose we had four and we wanted to get rid of one. So, we toggle our subtraction. And then this is 1 + 2, which is three. I know I went fast with the binary conversions there. I've done it enough where it's almost second nature. But if you wanted to pause and go through the sections I showed slower, you would be able to verify that this is all true. And now that we've done that, we have the issue as we can see and we talked about where changing the output changing the input immediately changes the output. And this is problematic because we would like to capture the output of our adder subtractor, our ALU, arithmetic logic unit, which I'll call the ALU here onwards. as if I haven't already done that in the video earlier, but we just learned that we have this flip-flop that we can use that can let us accomplish exactly that. So, I'm going to stop this simulation and going to zoom out a little bit here and let's use the flip-flop that was already provided to us. And I'm not going to skip the video this time because I think there is some true benefit to to seeing this. And I don't want to just keep confusing everyone by by skipping back and forth. Wow, this is not my nicest performance. Oh, maybe this is exactly what I did want. Yes, this is what I want. Okay, so what we going to have is we know that each of our flip-flops can store one bit. So, just as we had each of our full adders could add one bit, we're just going to have and our solution to add eight bits was to have eight full adders. If we have a flip-flop that can store one bit, our solution to storing eight bits is to have eight of these. And we're all going to feed them the same uh clock input line because we have some value on our output from our ALU and we want to trap each of those bits at the same exact time because collectively each of those bits is just a zero and a one. But if we look at all of them eight in a row, we know we can actually interpret a human readable number from this. So I'm going to create a new input that is going to be our clock. And that's going to get fed into every single one of these. I'm actually going to bring this down. And we're going to have eight of these. So I will have eight. And let me bring this up a little bit. I think we may need to bring this down later. And then we're going to get rid of our outputs here because they're actually no longer outputs. We will be needing them in feeding in each of these logic gates. So I'm going to delete this. And let's go ahead and wire in each of the data the D lines for our adder. So this is easy based on the construction I have. We can just bring these all the way down. And I admittedly did not need to bring it so far down. I thought it'd be a little more complicated. Um, but now we can feed this clock in to each of these. And on this software, you'll notice that when you have two wires overlapping each other, it doesn't mean they're the same wire. They can be distinct. They are the same wire if you have this dot. So you can see right here this wire is physically connected to this wire but there's no dot at this intersection. So they're actually two different wires. Okay. And then we have that. So let me then come down here and let's take our outputs of these and use them accordingly. So let's see if it's 90. Nope. 270. And I will have eight of these in a row. >> Okay. And then we should be able to And we want to look at the Q, not the inverted Q. Because as I mentioned earlier, we actually don't care about the inverted Q for the computer we're building. Okay. So now I'm going to run this circuit and let's let's see how we can actually use this. So let's say I wanted to add the numbers 1 + 1 and we would expect two. So I'm going to put in a one and a one. And our input our add subtract line is zero. So we're going to be adding and you can kind of see by looking at these lines up here that we have we have a one or a two as our result. Sorry. But we want to capture that result because the moment I start changing this input, you can see the output starts changing and that's not good. We want to be able to save what we have. So we know then from here that the whatever the input lines are, they only update to the output lines at the exact moment this clock goes from 0 to one. So if I set this from 0 to one, we should expect to see this bit be set cuz that represents two. And that's exactly what we see happen. And now if I keep changing this input, you can see that the outputs of this of the ALU are changing, but they're not going to get trapped as the stored value. The stored value is not going to update until the next time the clock goes from zero to one. So I'll keep changing this. Nothing happens. Set the clock to low. I can see even changing things has no input. And then now suppose I wanted to latch a new value in. Suppose I wanted to do uh 4 minus one. And I would get the output of three. And if we do that and propagate this through, then we Oh, it looks like I Oh, I messed up something. I did four and one, but I had the add line. So, that's fine. I will fix this. Let me set the subtract line. And then the moment the clock goes from low to high, now we can see this this three gets latched in here. And changing the inputs has no effect. And so this is very very useful because we're now actually able to store values. And that's that's something that we'd like to do in our computer. Our computer actually needs to store values. We have this effectively calculator up here, but if we can't save anything, it it's not very useful. And what we've actually built here is not just eight flip-flops. This entire thing is what we call a register. So a register is a abstraction over a flip-flop. It's multiple flip-flops together, but we don't we don't perceive them as individual flip-flops. We looked at them we look at them in aggregate. And each of these flip-flops get in their own inputs, but they all have the same clock line and then their outputs are all read together. And if you've done a little bit of computer programming before, specifically in the language C, you may or may not be familiar with the keyword register. And if you're defining a a variable in a programming language, which if you have no idea what I'm talking about, don't worry about it. If you define a variable in a programming language C and you mark it with the keyword register, then it instructs the compiler to try store that value in a register instead of in your computer's RAM, which is what we'll come up to next. And this is because these registers are very very fast to read and write from. You can see they they operate as soon as the clock goes from 0 to one and then their values are immediately persistable. What we're actually going to do next in this video is build up RAM for our computer so we can save values that we add into different spots in memory. And you'll see when we actually go to use it that it takes more time to interact with memory from RAM. And that's because you would have to figure out where in RAM you want to go and then pull that value back out and then put it into a register. [snorts] So there's a few more steps involved. But before we build RAM, I'd like to show what would we could do by taking the output of our register and then chaining it as the input to one of the arithmetic logic unit sides. So I'm going to stop our program here and I'm going to copy this cuz I I'd like to keep it. And what I'm going to do is destroy these and destroy I just want to destroy. That's not possible. Okay. But I'm going to take our outputs, our register value, and make it the input to the ALU. And what that's going to do is that the it means we're always going to be adding or subtracting the current value that's stored in the register with whatever our input is. So now we only have one input value and we can add or subtract whatever value in the register is. We'd pulse the clock and then it update the register with the result and we could do another addition on that. So let's build this and then we'll see what I actually mean here. Okay. So now something interesting happens if I if I start this circuit. And it's it's weird. We only have we have one we have one one input here. And I've I've done a poor job of designing this. But you can see that our our register is also outputting a zero right now. And what I can do though is let's say I add one here. Then we're we have since a register is storing zero that means our our input a side is zero and then we're adding a one and so we can see here the result is a one and if I want to pulse that in clock then we can trap that value in the register so I do that and now you can see that the register is outputting a one and let me actually pause this one more time because I think it could benefit from some actually labeled outputs. Okay, this is a better representation. But so we started off with we have a zero on our output which is also our input A. So now we add we want to add one to that and I'll pulse the clock from low to high. And now we get a one as our output. And notice if I keep one on this circuit, then now we have our one here and we're we're keeping it as a one here. So then the next time this clock goes from low to high, I should expect to see 1 plus 1, which is two being on the output of the register. And we see that happen. And now I have two here and two is our first input and one is our second input. So I should see three, which means this and this should be set the next time the clock goes from low to high. That's exactly what happens. And if I keep pulsing this clock, we have three. and then I'll go to four and then five and then six and then seven and then eight and it would keep on going. But what we have is a circuit that lets us count. And this is going to be useful. It's a sake of illustration for now, but later in the computer we're actually going to revisit this. We we are going to have a part of our computer which just incrementally counts and it's counting up and up by one at a time to know what instruction i.e. what work it needs to do next. But that's not something we need to worry about for now. Uh I just wanted to put this in to maybe give a little bit of context about our our ALU. And we can also count back down from zero. So we have eight. If I toggle the subtract line, now we have eight. And every time I pulse the clock, we're going to be subtracting one from the value. So I go to seven and then six and then five 4 3 2 1 and then we're back at zero. And interestingly enough, if I subtract one again, then 0 - 1 should be negative 1. And this is actually the binary representation using 2's complement of negative 1. So this is very interesting. So now what we'd like to do is operate on multiple values. So we would like ideally to be able to perform large and more complex expressions. And what I mean by that is right now we can either do a + b or a minus b. And I'm not suggesting that we're going to do multiplication or division because I said that's probably out of the scope for our video because of YouTube's upload limit. But what we would like to do is a + b minus c plus d. Something that involves more variables than just two. And the only way we can do this with our ALU is if we had a certain way to store memory beyond one register because we're always going to only have two inputs to our ALU. And what we'd like to do is just be able to control what those inputs are based on looking up values in memory. And to bridge this gap, we're going to build what we call RAM. And you are probably familiar with RAM independent of how well you know computers. And RAM stands for random access memory. And so the way RAM works is that we will be able to give it an address and get back a value. And we'll either be able to give an address and get back a value. And that's when we want to read from our RAM or we give it an address and a new value. and the the RAM unit will update whatever is in memory at that address. And what I mean by address is we effectively have a table of values. So what I'm going to do is switch back to my drawing screen for the next segment of this video so we can make some sense of this and then we'll come back here and see if we can build it out in hardware. Okay, so we're back to the iPad. Let's recap where we were. So, we had um this ALU, arithmetic logic unit, and you'll often see it denoted in this V-shaped form, and it kind of means input one, input two, and then your output. And I know we're ignoring some stuff like the add subtract flag, but that's just for sake of demonstration. And we had a our output of our ALU coming back around into a register and then that would actually feed into one of the outputs or back into one of the inputs and then this other input was controlled by us. And what this let us do and there's also this like clock signal or latch signal for the register that I'm also ignoring just for the sake of visualizing. What this let us do is keep operating on one value that was persistently being stored in this register. So the output of the ALU we'd freeze it and then we could do something um that we call that add any term our result and then we could say if I want to add one I could throw in a one here or if I wanted to subtract two I could throw in a negative -2 here and then I'd let that propagate through and capture the output in the new register. And the issue with this that we're seeing is well there's no issue with it but it's kind of simple and that we'd like to be able to do more. So instead of having one value um that we can save, what if we had like a whole ton of values over here and we had like several values like value one and two and three and keeps going and then at any point we could say hey I want to take uh whatever is at like this value three and feed it into our ALU do some work and then maybe take the output and then uh have that output go back and we write it into say like address one or something. Um, and this is kind of abstract. So, what we're going to do is figure out like what this actually means. So, for now, what I'm actually gonna say is let's throw away all of our thinking of the ALU and just focus on this thing over here because what we want is a way to be able to store data. And I talked about this just a few minutes ago, but um, yeah, there's going to be some replication here, but let's try to figure out what this this part actually means here. And the first thing you'll see is we're talking about storing values. And your mind's probably jumping, hopefully it's jumping straight to registers. Like a like if we want to store a bunch of values, let's just have a bunch of registers. And that would be the correct intuition. So let's say um we want to have several registers storing values. But before we even get there, let's just figure out like what this might look like on a table. So we we have several values that are all unique and so we want like a table to represent like what the state of this memory unit looks like at any given time. And so we can have this like this list of entries. So like maybe the first entry has like value 0 0 0 and the second entry has value 0 1 1 0 and the third entry has values 1 0 1 0 and the fourth value maybe it's uh 1 0 0 0 and so on. These are just random values and it actually turns out not to get ahead of myself when you plug in your computer for the first time and start it up the RAM takes on any number of values. the actual values specified in memory are kind of just subjective. Um, we usually reason about them starting off as all zeros when you first plug in a computer. And I don't want to get too lost in specifics, but that is an interesting thing. Um, if you like plug in a RAM unit and then try inspect the values right away, you'll see like sometimes they're all over the place. Um, and so let's say in this hypothetical we have three, five different values here. Um, we need a way to assign each of these values some unique identifier. Um, when I'm when I want to read like this value right here, that's a bad arrow. It's kind of Let's say I wanted to read this value right here. I need a way to tell the RAM unit, hey, I want that that second value in that list. And I either want to read read what that value is or write something new into that position. Um, and so what what is that like? We how do we actually represent that? And that is what we call an address which is pretty straightforward if we like how we can reason about the addresses is just what position we are in our list of numbers. So whereas this this right hand side has the value at a particular address the left hand side specifies what the address actually is. And we'll start counting from address zero. And so we can say this first value has address zero. This second value has address one and so on. And this can keep going. Um, and so now it's easy for us to ask the RAM, hey, give me uh RAM, give me what's at this address 2, and it would correctly return one 0 1 0. Or I could say, hey, write some value into address one. And that value is 0000 0. And uh the RAM after that operation would write that correct value into this address. So um that's how we represent things. RAM is a series of addresses and values. And you can kind of notice that there's there's two things that vary here. Um the first and kind of obvious one is is hinted by here and I say a dot dot and how many values do we actually store in RAM. So I guess our our tunables to say our parameters when we're designing our RAM system is number one uh how many addresses and the second thing is for any given address and this might not be apparent but it might be more subtle. Uh right now I just said each address has four bits like that's how at each address the value that we store there is four bits. um that's arbitrary. I just did that because that's easy to draw out. But uh what is the actual like width of the values at the address? So um bits of values. So uh for a given address, how many bits are we storing there? So for modern computers, this ends up being uh larger numbers um millions and millions into billions of addresses and each value is is a 64-bit address or even some computers it can be even higher 128 bits. Um I'm actually going to get to the point where we we build up a fully functioning RAM in the same software I just came from. So I'm going to keep the value small here because you can learn the concept without getting lost in the uh specifics of trying to make it one to one with the computer we're going to build. So I'm going to build a simple version of RAM that says uh let's say it's going to put the number we'll say four different addresses and then for also each address will store a four bit value. Um these two numbers do not have to be the same and I'm just doing that because it'll make our construction simpler here. So if I relook at this table now given this um we have addresses 0 1 2 and three and then in terms of the values let's just make up some random values. Uh let's just say this is the state of our RAM at any time. Um, and now let's get into the construction. So, we kind of suspected we were going to have registers to hold these actual values, and that would be correct. That's what we're going to get to. Um, so let's say we have a register for the first value, and then register for the second value and a register for the third value, and then finally a register for the fourth value. kind of made my spacing wheel too big here. But um, let's now talk about before we actually get into construction. I got a little bit of my a little bit ahead of myself there. Um, the two operations we have to RAM. So this this table diagrams the internal state of RAM and how we think about it. And we know that like under the hood once we build this out it's all going to be a mess of logic gates. But this is the the the values that are underlying underlying held in those logic gates. Um, so RAM has two operations and they're surprisingly straightforward. Um, and you could probably also deduce it by now. So the first one um operations. The first one is read and it takes in an address and then your output is going to be a value. So in our example, if I called this read function and said I want to read what's at address 2, then the RAM, if you told it that, it would give you, if it's built correctly, it should give you um 0000. So that's the first half of RAM, being able to read the values that exist. And then if we could only read values, that would be cool. But uh part of the thing we wanted to motivate in our previous example was being able to take the output from our arithmetic logic and possibly write it back into one of these values. And so you could probably guess the second thing we want to do, the second operation we'd want to expose is called write. Um, and write takes in a value that you want to write into RAM. and then the address that you want to write that that value into. And there's there's really no output here. Um, it just kind of it happens. You don't get anything from RAM and return really. Um, so in our example if I called this write function and I said hey write the value uh one one one into address let's say address two then what we'd expect to happen is that in this address we'd end up with one one one and then if I came back and called the same read operation we did earlier I should expect not to get 0000 0 I'd expect to get 11 one1 because that's the new value we just persisted in So these are the two basic operations of RAM. But it turns out that's also the complete operations of RAM. There is truly nothing more to it than the ability to read from a certain address or write a particular value into a particular address. And I'm going to clear this out. We are going to start with the read because the read and the right. Well, the write's a little more complicated than the read, but you kind of if you understand how reading works, writing is not too much more complicated. Um, so we're going to start with the read. Uh, and now with that proper context, I'll jump back to these four registers here. So, let's say this is our RAM. I'm just drawing around here. Um, let's say for the read operation we need to specify an input which is our address and that would go into this RAM and out of RAM we'd expect to get some 4bit value back. Um, and now here's where things get a little tricky. How do we actually do this? So we understand how these registers work and we understand that they hold values. So let me do a little bit of erasing. move these over. And let me also show the values that are in each of these registers. These are all just fictitious values. Okay. So the first thing is how do we uh capture this input. So these addresses 0 1 and 2 and three are just they're they're base 10 values. Um, so I can denote that here to keep it clear. Base 10 recall is just how we reason about numbers as humans. But we also learned uh several times now that computers don't really understand these values. computers especially the one we're building think in base two. So our addresses are actually have to come in as base two values. So let's let's for the sake of uh understanding here um let's go ahead and make our add a new column to our table which just shows the address in binary. So address and then in base 2 and then this address that we've been reasoning about is in base 10. And so we have four different values and uh I'll just spill out the answer because it's not too complicated. um we're just counting in binary here. So these are the binary values and you can see to encode these four different values we need two bits. So when we're thinking about address into our RAM unit we're looking for two binary inputs. So

That will actually be the representation of our input here. So we'd expect uh on our input, um some value that is two bits. And I'm going to bring that up here, and you'll see why shortly. And, um, this will be human for now. Eventually, we'll automate this entire thing when we finish the construction of our computer. These will be values that we can specify.

So I can write 01, and uh, I'd hope to get uh this second register. So this one right here. Um, I'd want that output to flow through. So, um, that's how we represent our input. And then we know our output. Since we're storing four-bit values, the output, we'd expect to just be four bits. And so if the user specifies 01 as their input, um, we'd want the values in this register to flow into this, into our output representation. And then if I switch that input, let's say to 00, we'd immediately want the values that are in this register to flow out to here.

So let's figure out this first arrow that I've been drawing over here based on whatever the input is. How do we correctly select uh the right register that we want? And so we're going to learn uh a new type of circuit. It's not too complicated, but it has a a word to it. Um, it's called a decoder. So a decoder says for a given input, we will decode that in spec, like pick exactly one output. Um, and so what does that look like? Let's start by giving each of these registers their addresses up top. So we start with 00. Here's 01. Here's 10. And here's 11. And that'll just help us for referencing. And let's also extend these wires that capture the input all the way down here. This will make sense shortly. Um, and recall that, you know, if I, if the user puts a one here, then no matter where you fork from, you're getting a one on this value because it's a wire. So, it just carries that value uh as far as it can.

So, um, let's start with this register 00. I'm going to spill out the answer to the first one, and then we're going to figure out why it works and then go from there. So, what I will say here is that we want some, we want this register to be selected when both of our inputs are zeros. And so, the way I'm going to do that is I'm going to invert both of the signals. Remember, this is the not gate. And then I'm going to feed it into an AND gate. And now we have something interesting. So, I, I, you're probably confused how I got here. Let me prove to you that this works first. So if both of our inputs are zero, we're going to get a zero here and a zero here. When we invert it, we get ones because the inversion of a zero is a one. And then for an AND gate, it only spits out a one if both the inputs are ones, which happens in this case. And we get a one here. And you can kind of see that for any other combination of values, the output of this, this on this line at the end here, is going to be a zero.

Um, so, for example, if I threw in the input, if the user had specified the input 10, then what would happen here is this top inverter would spit out a one, this bottom inverter would spit out a zero. And then one and zero. Since neither, since not both of the inputs are ones, we'd spit out a zero here. And I'll let you uh work backwards. And if you want to trace through every possible uh case of the four input combinations, you'll see that the only time that this line right here gets a one is if both of the inputs are zero.

Um, there's another way to think about this too is work backwards. So we, if we want a one on this output line, then we can, we can work from right to left. So we'd say if this AND gate outputs a one, it means that both of the inputs must have been one by the definition of the AND gate. And then for this inverter up here, if the output is one, then the input must have been the opposite of one, which is zero. And the same would follow for our, our gate down here. And then you can kind of see that the only time that we could possibly end with a one over here is if both of the inputs are zero, which I think is a pretty neat way of thinking about this. So that would correctly let us pick out this first input.

And then let's try go do the same for this next input. So this next input, we'd only want, we'd have some line here. We only want this line to have a one if the user has 01 on their inputs here. So what I'll do is we'd want something very similar to what we have above, but maybe we drop some inversions. So, we'd want this to be a zero and this to be a one. So, what I'll do is I'll invert this zero, and then this one would just feed through, and we'll just funnel it into an AND gate. And we have this wire out here. And so now you can kind of see again that the only way this can be a one is if both the inputs of this AND gate are one. And that means that for this inverter up here, if the output of the inverter is one, that it means the input must have been zero. And for this line right here, it just, it just pulls in from this uh, this input from the user. The only way that could be one is if the user had specified one there. And you can kind of see that's exactly what we have going on here, which is pretty interesting.

And we can then do the same for the next case. So, uh, now we want to do 10. So we only want this output to be a one if our input looks like this. So 10 means that this should be a one and this right here should be a zero. So we can invert this one and then feed both of these into the AND gate like we've been doing above. And you'll see that it's kind of just the uh, the this top one and this bottom one are just reflections of each other. And that kind of follows from the fact that the 01 flipped is just 10.

And last but not least, uh, our very, our fourth and final register. We'd only want that line to spit out a one if both the inputs are one. And this one's straightforward. So if, if we, if we want both the inputs to be one, we'll just AND them directly. So the only way this can be a one is if both the inputs are one, which should imply that the user had selected 11.

So this is pretty neat. What this means is that for every value we put in here, we will get only exactly and only one of these four output lines will be turned on, and that is really neat. So if I specify 00, then this will turn on and the rest of them will turn off. If I specify 01, you'll see that this one turns on and the rest of them turn off. And that keeps going. For 10, we'd see off, off, on, off. And last but not least, if we had 11, it'd be off, off, off, on. And so we've kind of built this selector-esque circuit that says for no matter what the input is for the input, we will correctly turn on only one of these output gates. And that'll pretty much be our cue for the register to then say, "Hey, if for each register, it can say at any point in time if its corresponding selection line is on, then it wants to pass its value to the output over here."

And this is pretty interesting, but what does it actually mean uh to now pass the output? That's where things get tricky. So, we've dealt with the input side. For the input side, uh, we have this, it's not connected to our registers yet, but we have this circuit that lets us say, uh, lets each register kind of know if it should be pushing its value to this output line. Now, we need to figure out how to look at that signal, i.e., look at that line, and if it is set, i.e., it is one, then how do we actually push the the value in the register at that current time to the output lines?

And so let's start with our bottom register. It turns out that this is pretty straightforward to do. Um, my drawing is going to get messy here, but we're quickly going to move on and build this in our our digital logic simulator. So, uh, it shouldn't be too much of a concern here. So, recall that our register um has output lines and how I choose to visualize this is up to me, but um, it has its output lines and pretty much uh, what I'm going to do is I'm going to take this signal and AND it with either each of the output lines. So, what I mean by that, let me draw it out.

Now, what do these outputs here look like? If our selection line is a zero, then we can guarantee that all of the output lines will be zero because the, these are AND gates, and we know that the nature of an AND gate says that if any of the inputs are zero, then the output for sure will be zero. So this is interesting because it means for this, we can verify that if our, if our current register is not selected, i.e., this line is a zero, then the output of these four AND gates down here will be zero.

Now, let's see what happens if we actually were to flip this to a one. Then we'd have ones. And I've kind of alternated uh putting these on the top and the bottom, which is my fault here. At least each of these inputs, the AND gate there, would be one of the inputs would be a one. And then the other input is just the value from that corresponding bit position in the register. And so when that happens, we know that the output of the AND gate is just going to be whatever the out, the the uh, other input is. So for here, this zero will flow through here, this one will flow through here, this zero will flow through, and here this one will flow through. And so now we can see that when the, the selection line is a one, then the output of these registers, the output of these AND gates, is just going to be whatever is in the register itself. And when that uh selection line is a zero, the outputs will be all zeros.

So this is pretty interesting um because it then means we can now, we know that uh if we extend this to all four registers, um, we, we can kind of get the uh, the same behavior where we have these, these four gates that spit out values. I'm not going to reconstruct the same circuit. I don't have enough space here, but uh, I can kind of box these in together. How about that? Oops. That should not. Okay, so this is, this is this the first register because I kind of have them close together. This is the second register, third register. And then we already have our, our fourth register down here, uh, that's just for distinction.

So if each register builds this property up, then we know that for at any point in time, um, three of the four registers, their output will all be zero, and then that last register, whatever one it is, will have the correct values uh being pushed through, i.e., whatever is stored in that specific register. And so then we kind of want to join these all together to the actual output. So let's look at the uh, the rightmost bit only for each register. So we'd want that rightmost bit from here to flow to this one. Um, and the same for the rest of them. And recall what I just said a second ago where for any particular address that the user specifies on that input line, three of those four lines, we don't know which one. It depends on whatever the selected register is. Three of those four lines are guaranteed to be zeros. Um, and that's because only uh, only one of the selection lines over here will be true at any time. And so that means for the remaining three, that their gates are just going to get blocked, as we just learned a few minutes ago. And so then it means that the last one, it either outputs a zero or one. And that's the one that we want to flow through.

So, uh, how we simplify that, we can't just have four of these lines going into um, into the output line is we can OR them together because when we OR these, if zero OR zero OR zero, the OR of the three that are off is always going to be zero, and then if we OR that with the correct one that we do want to pass through, the value will just flow through because zero OR X is just going to equal X. Um, so let's kind of show what that looks like. So for this specific one right here, um, we could take an OR gate and feed in the rightmost bit from each of our registers. And that will correctly let us capture, prop, push through the uh, correct rightmost bit position of all the registers to the output one. And that, that handles the rightmost bit. Uh, and my drawing, as I said, is getting bad. And we just do the same for all the other bit positions. So this second from right would just, we'd OR all of them together from all of our input registers. And that kind of captures our output.

So, this, it turns out, is the fundamentals of RAM and how we build reading RAM. Um, I've kind of gone a little bit fast here, and I'd like to keep it everything correct and thorough. And so, we're going to jump back and actually build this in our logic software. Okay, so I built the uh, very first half, which was the selector. So there's none of the register logic, no registers or output flowing through. But um, this was the very first part where we said, uh, based on whatever the input is, we'd expect only one of these four outputs to be true. Um, and we'd expect it to match the input. So we can kind of see that when we have 00, the very first one turns on, and uh, the next one would be 01. So if I keep this as a zero and turn this to one, we'd expect only this one to be on and the remaining three to be off. We can see that that happens. And then the next input was 10. So that, we'd expect if I flipped this on and this off, we expect this one to turn on and the remaining three to turn off. So that's true. And last but not least was 11. So if both of our inputs are on, we'd expect just this one to be on. And that seems to be true. So it looks like this first part is all good. So I'll go ahead and continue with the building there, reconstructing what we had diagrammed on my iPad uh in this software. In some respects, it is cleaner than what I was drawing on my screen, and in some respects, it's a lot uglier. Namely, uh, over here, this gets messy. Um, so, let's actually walk through and see what's happening here. But before I start the simulation, one thing I'd like to call out is that uh, instead of using actual registers, i.e., making a bunch of flip-flops next to each other, um, I'm just using inputs. And that way we can easily change the value that's in RAM just by clicking ourselves before we actually go and um, implement the uh, writing the writing part of our RAM, the second half. So I'm going to go ahead and start the simulation.

And this is our address selecting line. So right now, we can see it's 00, and the coloring here is pretty interesting. Um, you know, we can see some things light up, and it kind of corresponds to this, this selector part here. So first off, we correctly see that only uh, this first line gets selected, and we can see these AND gates are all fed uh, ones versus the others. All of theirs are fed zero, which means they're all outputting zero, independent of the value that's stored, you know, in in each of these RAM, uh, in each of these registers. But this first one's different. Um, correctly, since it's the address we're selecting, it's giving the data in these registers the ability to flow through. And so basically, this is our output line. And what I'd expect to happen if I turn on this rightmost bit position is that the output should show that rightmost bit position. And uh, that's exactly what happens.

So, um, how do we make sense of the uh, the mess that's going on over here? So, we know that uh, these are our registers, our four registers. They're kind of just uh, inputs right now, but they will become registers not too long from now. And then we also had our decoder over here. Uh, this decodes the input address selection and will select uh, one at a time of the correct, quote unquote, registers. And then we then join the value that's in each of these registers with the value of the decoding signal to determine which value should flow through each of our four output lines. And this happens at the per-register level. And then what we have to do is we have um, an output line for each bit position of each register. Is we actually need to go join them uh, to get the output for our, for the RAM unit as a whole. So if I look at this, this uh, let's say this rightmost bit position, we're seeing an OR gate whose input is two more, the whose input is the output of two other OR gates. So this is just kind of a four-way OR gate. Um, if any of these four inputs are true, uh, the value one will flow through and the output overall will be a truth. The software I'm using, as far as I know, does not have the easy ability to do um, OR gates that accept multiple inputs. So, this is kind of how I've gone the show around, but that's fine. It doesn't make our logic too much worse here. Um, and so, if this output corresponds to the rightmost bit position, what I'd expect is that the rightmost bit position from each of our four registers should be the four inputs to this. And that's kind of what we see. So if I turn this on, we can kind of see, hey, this green over here flows to this one. And then this line right here flows to that top register, the top output of the second register, which hooks into its rightmost bit position. Similarly, if I look at our third register, here's the rightmost bit position. Here's that output. If I trace it up, it comes into that third OR. And last but not least is our uh, fourth register. Here's the rightmost bit position output. If I follow that line, which gets a little tricky to do, I can see it follows into the fourth bit position. And so because of this, the, the decoding properties combined with our AND gate uh, little trick there, we know that at any time, um, three of the four inputs to this quad OR gate is guaranteed to be off. Um, which means the fourth value will effectively flow through. So if it's a zero, the entire circuit will output a zero. And if it's a one coming in here, that value will just flow through. Uh, and this is pretty neat.

So now let's suppose I put in the value um, this value into the second register. So that's what is that? That's 2 + 4. That's the value six here. And if I then switch the address selection part of the RAM to read what's in this second register, then I'd expect that value to get reflected over here. So the address for this register is 00. The address for this one is 01. So to switch it, I just turn the second one on. And now we correctly see that the uh, the output of our RAM um, corresponds with the register denoted by our input address selection, which is pretty cool. And if I then turn that back off and go and select uh, address zero, then I get that original value um, correctly outputted here. Similarly, if I were to select uh, the [snorts] third register, the register whose, the address in RAM uh, corresponding to 10, this third one down here, we can see its output is all zeros because the value of that register is all zeros. If I flipped it one bit at a time to turn all of them on, we then go ahead and you can see that the output turns on. And uh, just for sake of completion, let's go with this for our last, our last register. And this is address 11, one in RAM. So if I select 11 on our input select, our input address selector, I get the uh, exact value outputted here. So this is pretty cool. And we notice that even as I select uh, different addresses, that the values in RAM are held, but we're just only letting one of them flow through at a time. So this is pretty cool. We have four different 4-bit values. They just exist as is. And based on how we specify an address in our control input, we get to read the value of RAM for that given address at any time on this output line. It's pretty powerful.

Um, the next thing we'd like to do was we can now read from RAM, but we'd actually like to be able to write in values into RAM. So, what I've been doing for this demonstration is just uh, toggling the values here, and they're just kind of input units. But we really know that these uh, this shouldn't this shouldn't be a, you know, four input units. It should just be a four-bit register, which boils down to four flip-flops. So, what I'm going to go ahead and do is uh, we, what we want to do next is actually replace each of the inputs that I've mainly spent with uh, flip-flops. So, I'll actually show the first one. Um, let me get rid of these. And if I go over here in the tool, this is less relevant. Uh, we want a D flip-flop because that's what we learned about previously. Go ahead and rotate it. Oh, wrong way. And that's one bit position. We know just a register is just uh, a four-bit register is just four flip-flops next to each other. And then I'll hook up the wiring. So recall that uh, in our digital software, we get the output of the register is denoted Q, and we also get not Q, which is the inverted value. We only care about the value as is. So we'll just stick with Q. And cool. So now we've replaced um, instead of selectors, we've used actual flip-flops. So I'll go ahead and do that for the rest of them. I'll go ahead and replace each of our selectors with actual flip-flops. And recall that when we chain flip-flops together, just stack them next to each other, we get um, registers.

So now the next thing is how do we actually go ahead and make it such that we can write values in? So we have the reading of of our RAM working. How can we actually write a value into one of these registers? So let's start just by saying that uh, these over here can be the four bits. So if I were to want to uh, you know, oops, it's not going to let me run this. If I were to want to uh, write in a new value to a particular address, then what I want to do is be able to put punch in that address here and then punch in that value here and then have that um, be the signal that tells our RAM unit to actually go ahead and, hey, like, do this write operation. So there's two things to note here. The first one is that if these are our, if this is the input for um, reading a value in to RAM, then we can hook this up to each of our registers pretty much like the only way to replace a value in a register is to specify it on this on these four lines just by our construction here. So uh, the same way we can loop this, this right bit into the input line uh, for each of our right bits of our four registers, and I won't do that right now for the sake of uh, time. I'll do that for each bit position. So that's observation number one. So each of these registers, whenever it is going to update its value, it's just going to look at whatever has been set by the user. And right now, that's just going to be set by the humans. Eventually, we'll get to the point that the computer sets the values itself because, you know, the computer is fully autonomous in that sense, but that's uh, we're still a little bit of ways away from that. And that's the first observation. So I can go ahead and do that wiring.

The second observation is uh, I know we've talked about registers a little bit, and we're a little bit of back, but and we're going pretty quickly here, and it's that even if we hook in the input here, so like if I had, you know, each of these four bit positions lined up here, um, the only way to actually get uh, the value, the register to accept the new value is by that clock signal. Um, so recall there has to be like a, a clock edge, a transition from low to high or high to low depending on what flip-flop you're using. Um, and so we're going to add one more input here. And that's going to be uh, kind of this, I guess we'll call this like this, this trigger operation. Um, so if, if I wanted to write a new value into a particular address, I'd punch in the address here, would punch in the value here, and then because RAM needs a, because registers need a clock edge, rising or falling, to be triggered, I'd have to then punch this. And at the exact moment I punch this and it triggers a transition from high to low or low to high, the correct register uh, would hold in that value. So we said that for reading in the data input for each of these registers, it's going to come from these lines. So we can hook these input lines to each of the registers. But we can't hook the clock line um, into each of the registers. And the reason is is if we did that, then the moment we punch this clock line, the values here would get written into every single register. But when we punch the clock line, we only actually want to write the, write into the register that's uh, being referenced by this address setting line right here. So recall that we built the decoder to actually solve this problem already. So we can kind of reuse that. We know that at the exit, the output of each of these AND gates that we have on this vertical um, it'll only light up if the address selected by the user here is, quote unquote, picking this register. And that was for reading, but we're going to use the same logic for writing. So what we'll actually do is take advantage of that same principle that we have with the each of these AND gates. And that will AND the decoder output with this, this uh, clock line and feed that as the clock line into each of these registers. And what that'll allow us to accomplish is that when we punch this clock line, it won't actually replace the value in all of these registers. It'll only replace the value in the register whose AND gate uh, here, i.e., the output from the decoder, corresponds to the input set on these lines right here. So uh, I think demonstrations will make this clear. Let me go ahead and wire this all up.

I've gone ahead and finished up the wiring. And uh, a few things are going to look different now. So I've kind of moved some of the stuff around from when I cut the last video to make it fit. But um, you'll see that this is our value input line. So when we want to write a new value, we set the value here. This is the same. When we want to read or write to a register in RAM, a specific address, we punch in that address on these two bits. And uh, last but not least, you'll see that this is the clock signal. So uh, in our diagrams, we're using positive D flip-flops. So that means that this register will latch in a value uh, on a rising edge of that clock signal. So whenever the C line goes from zero to one, uh, that's the exact moment that the register will actually look at what's on its input lines, these D lines, and hold that and record that as the new value that it persists. And so if I zoom out a little bit, we can see that this is our input value. So when we want to write a new value, we place it here. And you can kind of see that uh, it is simply fed in uh, left to right, the same way on all four of our registers. So since these four lines are the only way to specify a new value, we can just hook each bit position of the register, i.e., each bit, each latch, um, or sorry, each flip-flop to the correct uh, position on the line here. And then we said we could not do the same for the clock signal because if we did that same thing for the clock signal, then the moment we punched it and went from a low edge to a high edge, uh, all of these registers would read in the new value that's on these four lines, which would write to every single address on our RAM when we really only want to write to the address denoted by the user selection here. So that's enough talking. Let me go ahead and run this circuit and turn it on and let's see what happens.

So the first thing to note is that if I look at the output of each of the registers, then you can see they're all all zeros. So that's just the way that uh, registers uh, initialize in this software, which means that if all the values in our RAM are zero at every address position, then no matter what address position I put in here, uh, the output's always going to be zero. But that's not very interesting. What we want to do is if we know everything's at uh, zero, let's go ahead and write a value to a specific register. And uh, we'd expect that when we select and selected that register, the uh, output would be captured here or the value of that register after we perform the write instruction. So let's write this second register. This register is the first one in our, our RAM. So that's address zero. This one is address one in our RAM. So I'm going to punch in address one. And then let's say we want to write all ones to it. Uh, 1111 in binary. Um, which I believe is 15. 8 + 4 is 12 + 2 + 1. Yep, that's 15. So we have 15. We want to write 15, the value 15 into address one. So we've specified those two things. And what we now need is a rising clock edge. So I'm going to punch this. And the exact moment I punch this, two interesting things are going to happen. First, the value 1111 should be captured in this register. So you'd expect to see these four lines light up. And then since uh, we are selecting this address still and not changing that this output line is all, is still going to be reading what's in this register. So we'd expect 1111 to now be the new value in the register. So if our implementation is correct, we'd expect 1111 to appear on the output line. So let's go ahead and trigger a rising clock edge to see that. And it, everything looks correct to me. We have 1111 as the value in the register and all ones um, on our output line.

So let's do two things. Let's clear this just for visibility sake. It doesn't really matter. We don't have to because we know that the next time uh, the values on this line are going to be useful is the next time our clock signal goes from low to high. And it's at high right now. So I'm also going to push it back to low. And that's also not going to do anything because of the discussion we had on flip-flops earlier. But now if I go back to address zero, it correctly has zero. That's where we started. And in fact, all the other addresses are still going to spit out zero. What would be interesting is if I specify address one, I'd expect to see 1111 on the output. So let's do that. And we can now see that we are correctly selecting the right output. So this looks good. Um, let's go ahead and punch in values to uh, the other registers just to make sure. So we'll start with this one, uh, register zero, uh, the first address spot. So 00. We already have 00 punched in here. And let's say we just want to write the value one to it. Then as soon as I push this, we'd see a rising clock edge, 0 to one. And we'd expect that value to get latched in here. And then since we're still selecting one, um, since we're still selecting the address zero, we'd expect to see that on the output side as well. So, let's go ahead and do that. I see one and then I see one. So, that looks good to me. Um, let's now I'll undo this and unset that. Let's write a value into the third register. Oh, so we can actually say I need to check that we haven't broken anything. So, we know we wrote one here and one one here. So, if I switch to this address, I still see 1111. And uh, let's go ahead and uh, write to our last, our third right of storage to make sure. Um, so that's address 10. Let's say I want to spit in uh, 11. Then I'll trigger that rising clock edge. We see that as soon as that happens, 11 gets written into the register. And we also see that being reflected on the output line. And we can go ahead and do this for the final register um, by let's say we want to write this value into it. Uh, we specify address 11, one, and that is interesting. So I wasn't expecting it uh, to actually read in any value. Um, so let me see what's happening here. My mistake here. So I, I misspoke. What I originally said is that uh, when the only way we can actually write this value into a new register is when this goes from zero to one. Uh, I actually have a clarification to make that uh, that's actually not the case. Um, ideally, after we write a value into a register, we should put this uh, read signal back down. The reason is is let's say I wanted to write a new value into address 111. Um, let's say I wanted to write the value 1111 into this final register down here. So, if I switch to this address and this is already high, it's going to cause a right to happen. And I'll prove that to you. Let me switch to address 11. And we can see that the right happens because that's the value being reflected here. But, uh, that's actually not what we want to happen. And at first, this appears to be a violation of what I said that latches, or sorry, flip-flops only write, hold in a new value um, when you go from a low to high clock signal, but that's actually, we have not violated that, that is still true. So if I punch this back down, let's say we want to write this value into that register. Um, and when I, what's interesting is when I, even if this line is set to high, when I go and push the right address of 11 in, what happens is that that triggers this AND gate here. Um, so this uh, this the selector will then get the right value to see, hey, one is set and one is set. So it comes through and uh, originally this AND gate was outputting a zero, but then it outputs a one and it goes from a low to a high, and that output of that AND gate is what we're feeding into the clock signal, not actually just the clock signal itself. So that's why that happens. Um, so we should be careful that uh, once we write a value in, we should push this signal back to low. Um, and that way when I swap to address 11, this time I see that the value on the input line isn't uh, getting written to immediately. In fact, it's not until I click this and trigger the rising edge that that happens. And the, the nuance is then that now that I've done my write, I should push this back down to avoid uh, the issue I just described happening over the ALU, the arithmetic logic unit, that we built, probably about an hour ago. And I made a few modifications. So first, it was adding on 8-bit numbers and therefore putting out 8-bit results. Since our RAM only stores 4-bit values, I've go ahead and cut this ALU down to four-bit values only for both inputs and outputs. And then the second thing I've done is I've made both the inputs to the ALU be registers and just let the output be as is. And uh, basically the reason I've done this is because what we'd like to do is connect the ALU and the ALU and the RAM together. And so what that might look like is I might load one value from a particular RAM address into this register. Then put on a different address in the selector, load that value into this part of RAM, into this register. And then I let the arithmetic happen. And then maybe I want to take the output and then write that back into a particular address in RAM. And so um, I've made each of these inputs be registers so we can read from different parts of RAM uh, without worrying about like arithmetic happening. Um, and then we'll deal with the output of this and how we can like that together. So uh, here's the output of our RAM. If we want to be able to read from RAM into uh, positions in this ALU, then what I could do is I could wire each of these output positions into the input positions of the registers that represent the input to the ALU. So we'll call this the A register and the the B register. Um, and so if I did that, you know, I have a full connection of these four to these four inputs and then these four to these four inputs. And if I wanted to load a value, what I could do is I could, you know, punch in the address here. The value would come up. It'd read into both these registers, but then because of the clock command, it wouldn't actually write into those registers until we'd actually pulse one of those. Um, so that would work and that would be fine. But the issue is that as we design this computer, there's going to be more components. And what we're doing is a one-to-one mapping of outputs to inputs that we know are going to exist. But let's say the RAM, like there's other things that might want to read from RAM. Then this would require us to also extend not only wires from here to here to here, but also from here to, you know, maybe somewhere else conceptually on this on this figure board. Um, and both of you, both these, like this gets to the same result. Like there's nothing wrong with this in terms of functional correctness. This will behave as expected. But you can already see here, you know, simple things require a lot of wires, and it's, it's, it's pushing the design limits with a lot of connections happening. Um, similarly, you know, like the output of this uh, ALU, if we want to write that to a specific position in RAM, the easy solution is to take these outputs and, you know, kind of wire them into the inputs here. But then, you know, what if something else in the computer wants to write, write into RAM, it also would then have to, you know, wire something to these same lines, um, that gets risky, you know, you don't want to be writing uh, different values on different lines at the same time by accident. Um, and so this generally becomes a, like design bottleneck here. So what we do is introduce the concept of a bus. And what a bus is in our example here, it'd be pretty much, it's fairly straightforward. It just be four control lines. And then for every component that wants to interact with another component of the computer, instead of wiring those two components to touch each other directly, we just wire those two components to touch the bus. And then um, if I want to read a value into this register, I would have the output uh, of the RAM write some value onto the bus, and then this register would just read whatever value is on the bus. Similarly, this register could connect to the bus too. And that way, instead of having a one-to-one pairing um, between everything that wants to connect to each other, each component just needs to have one connection to the bus, and that's all. So it's, you know, it's, it becomes like a one uh, connection per component rather than something that in the worst case could be exponential if every component wanted to connect to every other component. And this may seem trivial in the context of connecting RAM and the ALU, but uh, you know, now that we've, once we finished these two components, we're going to go ahead and add a few more simpler ones to the computer. Simpler in terms of understanding them, but still critical for correctness and actually making this computer run independently without us needing to punch everything. Um, so as long as you can agree or understand what's happening here, then um, that makes sense. So then similarly, you know, like if we wanted the output of RAM to be input uh, possibly to each of our operands for the ALU, we just write this output of RAM onto the bus. We connect RAM to the output of RAM to the bus, and then we connect each of these input registers to the bus as well. Um, and that works, uh, you know, we could literally hardcode these wires as is. Uh, and then similarly, you would want to say if we want to then write the output of possibly an arithmetic computation into RAM, we just connect our output here to the bus, and then we could connect our, our, our input over here to the bus as well. And that way, you know, if there was we had some result here and we wanted to write it, we'd, you know, let this value write to the bus. We, we'd tell, hey RAM, RAM needs to stop writing onto the bus. Um, this value can write it, it's what it wants onto the bus. And then uh, this value over here can, can read what's on the bus and then, you know, we punch in the right address and, you know, pulse this clock, and that'd be fine.

So the only thing to be careful about here um, anything can read from the bus. Reading from the bus is free. So literally to connect these registers to the bus, I just wired them in as is. But the issue is we have to be careful to ensure that only at most one thing is writing to the bus at a given time. It is totally fine if nothing is writing to the bus. But we'd uh, we cannot have two things writing to the bus. The reason this cannot happen is because you could short your entire circuit. So what happens if this wants to write a one to this wire of the bus and this is still just connected to the bus without any disconnecting capability. Uh, and this writes a zero to the bus. So what happens is if you're writing a one to the one to a wire and a zero to a wire, well, the wire, as we learned earlier, can only have a zero or a one, but you are simultaneously trying to write a one and a zero to the wire at the same time. Um, this, this is bad. This can't happen. It's going to actually, you know, it would, it would break your computer. So, I actually don't know the, the physics behind this too well about electricity itself. So, I won't try to speak to this too much. Um, I believe this is just called a short circuit. You know, connecting high to low directly with electricity uh, will cause

like a surge of electricity to flow through, and it'll just like blow your computer. Um, I'm not going to say anything more than that because honestly, I don't understand. But, um, that's what we need to be careful about.

Uh, the issue that I just described only applies when two things try to write onto the bus at the same time. I said that they only apply when you try to write onto the bus, uh, and not when you read from the bus. And that's because when you're reading from the bus, you're not, like, these components aren't actually putting out a zero or a one. It's just reading what's on the wire connecting to it. So, uh, reading from the bus is fine because you're not actually putting a value out there. The issue is when you put possibly contradicting information onto a wire.

So, how do we get around this? Is something called a in this case, um, we will what we'd like to do is simply, uh, if we know something is about to write onto the bus, uh, that and we want, we would actually want to, you know, establish that connection with the outputs onto the wires. Um, but if something is that something is in a state where it could write to the bus in the future, but it doesn't want to right now, we need to disconnect it physically.

So, uh, one way is, you know, simply destroy the wires and then reinstrument them when you do actually want to ride on the bus. That's pretty painful to do. So, instead, what we have is, uh, turns out this is a common enough thing that we can just use something called a switch. Um, switch. Oh, there's a whole section for them. And what the switch will let us do is it'll literally, you can kind of see this in this diagram. It might be a little small. Um, uh, if I click it, uh, it'll, you know, connect the two ends of the wire. So, here's your switch. You'd have something like this and then this. So, in this current state, these two wires are not connected. But then if I was writing the simulation, I clicked it, it'd drop this down and it'd connect two wires. And so that's pretty much what we're going to use here. When we don't want this or this to be writing onto the bus, uh, then we disconnect it. And when we do want to write its value onto the bus, we'd click it and it would drop down and establish a full connection.

So, let me go ahead and wire this up and then we'll come back and see what that actually looks like in practice.

Okay, so I finished wiring things up. A few changes I've made. So, first off, we had a lot of extra space here. Uh, I I condensed things in. No functional changes there, but just wanted to make things so I had to do less navigation and zooming around. Second thing you'll see is I've implemented the bus right here. It's just four ordinary wires. The A and B registers to our ALU read in into each of their corresponding data bits from this bus. Similarly, the output writes onto the bus, but it's gated behind these switches we've talked about. Therefore, we don't risk two different components running onto the bus at the same time, breaking our circuit and leading to an invalid state. And I've also updated RAM. So, the output of RAM also writes onto bus. And similarly, it's gated behind these switches for the aforementioned reasons. And on top of that, for when we want to write read values, uh, from the bus into a specific part of RAM, I've now connected our input lines which we previously had as toggles up here, uh, onto the bus. And then other thing I've done, I've added outputs to our bus so we can easily see the value on the bus. It's already apparent by like the dark green versus light green. I just think sometimes having this explicit signal is easier to, uh, see, especially if if you're watching this on a phone or something.

And then, um, the last changes I've made are up here. So the first one is for being able to, uh, write stuff onto the bus myself manually. I have these input lines and they're also connected by switches because that's writing onto the bus, which has to be gated against. And, uh, this is because when we turn on our computer, all of the registers, flip-flops in this software will initialize to zero. So everything in RAM will be zero. Everything in the ALU will be zero. So if we wanted to move values from RAM to the ALU, do some math, and then send them back to a different address in RAM, it would be, uh, inconsequential, um, because every value is zero. So when we turn on the computer or start the simulation, I'll use this, these manual toggles to write some values into specific addresses of RAM. And that way we can actually move them onto the bus and then into a register of the ALU, op one of the ALU operand registers. And then we'll actually have some sensical data about rather than dealing with a bunch of zero plus zeros.

And the last thing I've done is, uh, you probably noticed that we have a decent number of signals now. Uh, signals, flags, however you want to call it, but, um, basically we have several registers. So, you know, we need a a flag to write into the register A, a flag to write into register B. For our ALU, we have an add subtract flag. Then we also have a flag to update a specific address in RAM. Then we have two inputs, um, for when we want to select a specific address in RAM. So I grouped all of these up here. And I also wanted to call out that, uh, or highlight doubly so that these switches which control whether or not we write onto RAM are right now something that we'll have to click and toggle. Uh, if we use a different unit, we could, you know, kind of add that functionality, uh, as something we toggle here. Uh, maybe I'll do that afterwards. But what I wanted to highlight is that, um, these these two areas or three areas we write onto RAM plus these are all that we have to control.

And once we get this demonstration working, uh, a natural next question is like, well, okay, these things are all punched by humans. So like, how do we actually get the computer to know like, how is it, how could it be possible the computer could even know to punch certain things? Like, what is the computer meant to be doing when it's turned on? And B, if the computer had some instruction, uh, about what it should be doing, then how could we actually rearchitect this to make it such that the computer itself can be the one pushing these buttons? Um, and I I say that lightly because it doesn't actually look at that in practice, but, uh, the computer is not physically going out and pushing these. It just, it's wired into control. That's the output of some other decision-making part of our computer that we'll get to. Um, but I digress there.

So now what I'm going to do is go ahead and power this on. Uh, as I kind of mentioned, you know, everything is is all zeroed out. So if I, you know, if I pulse pulse any address in RAM, you can see that the output here is zero. And then the other thing that's actually new here is we've seen in this software that, you know, zero, uh, is this dark green and this brighter green is denotes a one, and we see that on all of our wires and stuff, but now for the first time, we're seeing gray here. Uh, and what is gray here? Gray would be the absence of zero or one. So now that we, uh, have things that connect to the bus conditionally, if nothing is writing to the bus at any time, then there is simply just no values on the bus, which is fine. It's just a different state that we, uh, we think about. You know, we're used to our our wires and all of our, uh, logic gates taking in strictly zeros or ones. And that is true, and that still has to hold true. Um, but, you know, it's not actually, you can have a wire. You can imagine this. It's not that difficult a concept. If you just had a physical wire that you held in your hand that was not connected to anything on either end, that would have neither a zero or one, uh, no amount of electricity on it. So that's what we're seeing here.

But, uh, if I actually want to put some values on the bus manually specified, then, uh, you can see I can toggle these switches which connects, it'll connect, you know, here's my input line to the this line of the bus, and then you can see that, you know, since we've now written values onto the bus, anything that connects to the bus and the bus itself now has zeros or ones on it.

So, let's say we want to, uh, write some values into RAM. Now, let's say I just want to do something simple like in address zero of our RAM, I want to write the value one. In address two of the RAM, I want to write the value two. And then I want to add that one and that two. I'd expect a three. And then I want to write that back to a different address in RAM. Um, how can we do this? So, first, let's use this manual hack I have. Let's write one onto the bus. And let's actually write, uh, that that value one. Let's read that from the bus into the RAM address zero. So we already have address zero selected. So that's not that interesting. And then all I need to do now is pulse this line for writing into RAM. And recall when we go from a low to a high, RAM will catch that value. You can kind of see that happening internally. You can see, you know, uh, we're not letting RAM write onto the bus, but if we did, it's trying to write the value one. So that's cool. That seems to work.

Now we want to write the value, uh, three two into, actually, let's, let's write an interesting value. Let's write the value three, um, into the next address in RAM. So I I put the value three onto the bus and let's write that into address 01. And, um, I messed up, uh, it already actually captured the value as you can see. Recall what we talked about 20 minutes ago. I should have let this value fall back to zero after I wrote into the RAM, but I didn't. Um, so I fixed that now. Put the the values in RAM. And now let me go ahead and disconnect our manual input from the bus and connect the output of the RAM unit onto the bus. And so now I can see if I select address zero on the RAM selector, we have the value one in address zero. And if I select address one, we have the value three. So we can see that we've correctly written these values into RAM.

And now that we've written values into RAM, let's get those into the ALU. So, let's put the value one into this register and then the value two into this register, and we'd hope to see a three. So I have the value one written on the bus because I have address zero selected. And now what I need to do is toggle the line to write into register A. So I'll do that. And now register A has the value one. I'll put that low. Now I want to write, uh, the register, I want to take what's in address two of RAM and write it into this register. So let's put address two of RAM onto this bus. At address two, we have the value three. And I'll now post the line for writing into register B. And when I do that, you can see there's now this three there. And so, um, now what I'm going to do, I've done writing stuff from RAM into these registers. So, I'm going to disconnect our RAM output from the bus. And now what we can see happening is that our ALU, uh, well, this was happening before I disconnected the bus. I just didn't want to forget to do that. Our ALU has the output of three plus one. And we can see that it's trying to write four onto the bus. We disconnected it though. So let's connect the output of the ALU onto the bus. And we see that the value four is out there. And let's write that back into a register. Let's let's say let's write it into the original address, uh, zero, address zero in RAM. Um, I'll do that by setting the correct address, uh, field. And then I will pulse the flag to write into RAM. And that should be done.

So, if I now disconnect our ALU from writing onto the bus and let RAM write its value back onto the bus, I can now see that with address zero selected, the value four is what's stored in there. Uh, and if I pulse back to the other address we set, we'd expect a three, which we see, one plus two. Um, and so, yeah, this looks functionally complete. Uh, and this is pretty interesting because now we're doing complex arithmetic. You know, we have four different values we can be operating with. So we can do A plus B minus C plus D, whatever we want to do by, you know, simply moving values from RAM into these corresponding registers, setting the add or subtract flag if we want to do subtraction, letting the ALU do its computation, writing that value back onto the bus, and then reading it from the bus back into RAM. And you can kind of see we we did something very sequential here. You know, this is very reproducible. Um, you know, to to write a value onto the, uh, to read a value from the bus into RAM, you have to, you know, specify the address plus the flag. Then, if you wanted to read a value, write a value from RAM onto the bus, you need to connect the the, uh, RAM output to the bus, select the right address, and then it'll be on the bus. And then, we wanted to read the value from the bus into one of these registers, we just do the same thing. We just post that flag. Uh, it's pretty interesting.

So, the last thing I want to show here is I said you can't write zero and one, uh, to the bus at the same time, else you cause a short. So we have the value, uh, let's look at this rightmost, the rightmost bus position has a one on it. Let's what see what happens if I put a zero on it and then try connect this zero to the bus. And when that happens, what you're going to see is that we're connecting a zero and the one, and I guarantee you the software is not going to like it. Perfect. Yeah. So more than one output is active on a wire causing a short circuit. Cool. So I was right that when you try to write a concurrent zero and a one onto a specific wire, it's called a short circuit. Um, cool. So that, uh, now concludes our ALU and our RAM sections. Uh, this is probably the trickiest part. Uh, it is a tricky part to reason about holistically. You know, you get into a a lot of logic gates, but, um, the rest of the stuff we, the next few things we'll do are far simpler and, uh, are just going to iterate on, uh, be things actually reductions of what we've already seen.

So, the next little bit of the video should be a bit chiller. So, one of the things that you might have noticed that can be kind of annoying during this process was, uh, trying to go from binary values to figure out what the actual decimal value was, uh, for a particular thing. So, you know, if we were feeding an address to our RAM, uh, we kind of had to like peek at these four lines and see which were set to then know what the actual value was. And that's kind of how we were sanity checking. Similarly, if we wanted to know what was stored in the registers for the ALU, the A and B registers, we kind of have to look at these four lines or these four lines and and figure out what's happening, uh, what the actual value is. And, you know, this is 4-bit values, so it's not too much effort to do it, but it can be kind of annoying to go to have to do that so much, um, especially when you're, you know, kind of early onto this and still bringing your intuition.

So, what if we had a way to actually just visualize the numbers? You know, we know computers operate in base 2 binary, but, you know, us humans, when we're debugging these machines or or trying to inspect the internal state at any particular time, be nice to be able to see like, hey, like, what values on the bus, uh, and I could see that, you know, just as digits without having to, you know, scroll in to the bus and look at each of the wires and, you know, start counting powers of two and adding them together to figure this out. And, um, for this, we have something called a seven-segment display.

So, I'm going to hop over here. Um, and this is something that you can see takes in a binary input up here, i.e., machine-readable values, and it'll it'll draw out the actual, uh, decimal value that we can see that we can easily reason about. And some of you may have seen this, some of you may have claimed to have never seen this before, but I guarantee that you actually have seen this. If I come over here, uh, this is a scoreboard, a picture of a scoreboard probably that you maybe have seen in your high school. And you can see that actually everything is a seven-seg seven-segment display. So, why do we call it a seven-segment display? If you look at each of these numbers, let's just pick this one here arbitrarily. You can see that there's, um, seven different lines that make up the display. So there's four up here and then three in the bottom. Four plus three, seven. And, um, by turning on or off certain combinations of these individual lights, we can create the illusion of drawing the number. And I wouldn't even say it's an illusion. We actually just are drawing the number. And, uh, this is a pretty simple way, you know, without having to get a whole LCD display, which we'll talk about later. Um, it's an easy way to draw numbers in a way that this is significantly easier to see that this is a two rather than trying to like do some binary to decimal conversions and reason about that yourself.

And there are things like, there's seven-segment display, there's higher number segment displays, um, and those can do more complicated things and maybe show symbols like the division symbol. Um, for the sake of illustration here, we're going to keep it to seven-segment displays. And we're also going to keep it down to just one single digit. So, uh, we know that our bus here is the one we've built is actually four bits. So, there's two to the four different val, uh, different numbers. Sorry, there's 2 to the power of four different values that we could write on the bus. 2 to the power of four is 16, which means we can represent with these four bits numbers 0 through 15. So, it turns out digits 10 through 15 require two of these displays if we wanted to. Um, the logic is the exact same, it just requires more effort. And so, we're going to keep it simple and say that like our display for now will only show the numbers 0 through 9. And, uh, you'll understand that if we wanted to have, uh, we could put two of these next to each other if we wanted to handle two digits, but it just requires a lot more work, uh, and doesn't teach you anything that you wouldn't learn, uh, by doing the one seg, the one individual digit display.

And so, this is what this chip looks like in real life. You can kind of see there's, uh, several pins on the bottom here. And turns out if you write a one or put power, these are synonymous things, to one of these specific pins, then it'll light up a corresponding part of the display. And so, if I look at a diagram, uh, that I found online for what one of these these physical units that you can buy, what that pin structure looks like, you kind of see that, uh, you know, we have these these individual lights labeled A, B, C, D, E, F, and G. It kind of wraps clockwise with the G being the last one. And they each correspond to a specific, uh, input pin. So, if I put one here and zeros for the rest of these, we'd see just this one light up. And you're also probably wondering, uh, well, we have inputs A through G. That makes sense. What is this DP and ground? Um, in this specific unit, DP will let you hit that decimal point. And then ground is just effectively, you need to give it power. Um, so it can complete the circuit internally. We don't really have to worry about that for the sake of what we're building here. Um, but let's actually see like what each number looks like visually.

So, you can see we can represent numbers zero through nine. And to turn to represent the number, uh, zero, we turn on A, B, C, D, E, and F. And we'd leave G off. And for the number one, uh, we just turn on B and C and leave everything else off. And you can see that we can kind of just draw out every number and pretty easily see what we need to turn on to get each digit position ready. So, what I've done is gone ahead and made that into a table. Um, we have our 10 different numbers that we're going to be capable of drawing with our single-digit display. And, uh, you can see decimal numbers zero, and then I have that in binary, two. And you can see that, you know, for zero, uh, you'd turn everything on except G. And if I tab back here, you can kind of see that's the same source of truth we have here. We can check one more as well. Uh, let's say the digit seven, you'd only turn on A, B, and C. So, if I look here at digit seven, we can see that only A, B, and C are on, and the rest are off. And so this probably looks familiar. This is the truth table that we looked at way earlier in this video. Um, and what I'd like to do is actually go back to our software and and build something out that'll let you specify your 4-bit binary value and it'll correctly light up the correct segments of the display. Um, so if I tab back here, I can see that my software that I'm using actually lets me have this. Uh, so I've wired in our display and it has, uh, you know, pins for each of the values. And so I can kind of see here's that A, here's B, C, D, E, F, G, and then the bottom right here is the decimal point. We're not really going to use it, so we don't really have to worry about it for now. But, uh, what I'd like to do is go from this truth table to logic gates that actually correctly light up the display.

So, let's see if I look at, uh, this position A here. Um, position A, then I can see that what numbers on the input line should turn position A on. You can see that's numbers one, two, or sorry, that's number zero, two, three, five, six, seven, eight, and nine, which is kind of what we see in this table here. If I look at the column for A, when should A be turned on? It looks like it's for every number except one and four. So, then what I'd want to do is if I had, you know, the four, uh, binary inputs coming down from the bus, if that's what we wanted to display at any time, then I need to do some logic where like, if the value of of the four bits represents any of those numbers, then this input line should turn on. And we do that for each of the, each of the different segment, uh, pills that we have on our display here. And it turns out we've already done something pretty similar to this. We built this decoder earlier for RAM where we have something, uh, it's easier because there's only two bits of addressing space for our RAM. But basically, we know that whatever value the user puts on RAM, we can correctly select the right index, uh, in our RAM. So, you know, uh, it's 0 0 right now, and we see this first position lights up. When I put in one, I see that second position lights up. And if I put in the maximum index, that's two plus one, three. And I can see 0, 1, 2, 3. Uh, index number three lights up. So, we've already built out this decoder logic earlier. So, we're literally just going to do the same thing, except this time we have to extend it, uh, to be four bits, which is a little more complicated.

So, what I'm going to do is bring our bus further down and build this off to the side here. So, I'm going to actually pause the video or just speed through this part, and and we'll we'll talk through the output. Okay, so I've gone ahead and built this decoder. And, uh, basically what I have, I detach it from the bus so it's its own unit. Right now I have a 4-bit input, and for each of those bits, um, I actually carry that input bit down and then also I carry a negated version of it all the way down. Um, and the reason I do that is because if I jump over to our RAM, basically what we had to do for our RAM whenever we wanted to negate a line was to manually add an inverter. And, uh, this means we end up using a lot several inverters when really, if we just used one inverter up here to create a forked version of, or two one per line, two different inverters to create a forked variant that inverts each of the two input bits, then we could have just had our inputs pulled in from these hypothetical lines directly. So, not only does it use fewer logic gates to do it the way we've done here, I'd also argue it actually makes things easier to read because we kind of know this means, you know, uh, leftmost bit and then the inverse of the leftmost bit, and then bit position number two, the inverse of that, bit position number three, the inverse of that, the rightmost bit position, the inverse of that. And so, you can kind of see then, you know, uh, this would correspond to zero, then one, two, and so on.

So, for zero, what I'm doing is I'm looking for 0 0 0, which is the inverted of all of the bits. So, 0, 0, and zero. And you can kind of see that, you know, uh, if I were to turn this circuit on and all the inputs were zero, then you can see all the inverted lines turn on, and then that triggers this this AND gate where it's looking for the the this bit positions off, this bit positions off, this bit positions off, and this bit position is off, and that's why we can see exactly one output lights up, and we've decoded this input. Um, and so similarly, if I turn this off, just for visualization, let's jump to the next one, which we'd expect to line up with the 00001. So, we can see there's the input, inverted of the first bit, the inverted of the second bit, the inverted of the third bit, and then the regular of the fourth bit. And that would give us, that's saying 0 0 1. All four of those have to be true. So now, if I powered this on and turn this to one, we'd see the same thing. And you kind of continue that logic all the way down. And we'll verify this is correct by counting through.

So, we tested zero and one. Now, if I plug in two, we'd expect this third output to turn on. That's case. If I go to three, we'd expect this to come on. Cool. If I go to four, I'd expect the next one to come on. Then five. Cool. Then six. Then seven. And then eight. And the last one is nine. Cool. So, it looks like zero through nine work correctly. And so now that I have an output line for each of the numbers, um, I can feed this into our seven-segment display. So, this simple one right here, this bit turns on. This is the A in our diagram. So, if I come here, uh, I now want to pull that to be, I want to OR all, I would like to logically OR together all the numbers for which this A should be on, which is 0 to, so 0, 2, 3, 5, 6, 7, 8, and 9. So, we will draw lines from all of those numbers that I just listed out. We will OR them all together using several OR gates and then feed it into this line right here. So, I'll go ahead and do that and then we'll, uh, come back.

Okay, so I've gone ahead and built out everything for all the logic for deciding if we turn on A, this top line up here. And then for all the other inputs to the seven-segment display, I've just wired it to this thing right here, which is called ground. It just means zero. It's a logical zero. So, it means all the other segments will be off. And if I jump back to our table that we started with over here, I can see that we'd expect this A button to be on for everything except numbers one and four. So, let's go ahead and pulse through each of the input combinations and verify that this works. So, we start off with zero. And this is on. That's good. Now, I'm going to put one, and we'd expect it to turn off. That looks good. Two should be on. Three should be on. Four should be off. That looks good. Five should be on. Six should be on. Seven should be on. Eight should be on. And nine should be on. So, this looks totally good. And we've done this together just by ORing together everything except the two values for which this segment should be off. So, that means if if one or sorry, if zero or two or three or five or six or seven or eight or nine is selected by the user, by the input, then we should turn on that one. So, this is kind of the logic, uh, and we'll go ahead and do this for the remaining ones.

Okay, so we have built this out. You can see there's a lot of logic gates. Uh, I probably could have done this more elegantly in hindsight, but, uh, should be working. Um, so you can kind of see for each of these, uh, what we did for this this A, kind of repeated for B and C, D, E, F, and G, ORing a bunch of stuff together based on the input lines and then feeding them around to this, uh, seven-segment display. And also that control bit for the dot, we just hardcode to zero because we're not going to use it here. So, let's go ahead and make sure that this works. So, I'll go one, and then I'll count to two. That looks good. The next is three. That looks good. Then four. That looks good. Then five. That looks good. Then six. That looks good. Seven looks good. Eight looks good. And last but not least is nine. So, we can see that 0 through nine work as expected. And then, uh, our logic gets set up so they work for 0 through 9 correctly. We said we're not going to consider multi-digit, uh, numbers for now, but just out of curiosity, what happens if I tried to put in 10? And you can kind of see, uh, just by chance, you're this one lit up nothing. Um, 11, 12. Okay. Yeah. So, um, I was expecting gibberish output, but that actually works. So, yeah, we can see this this works as expected. You didn't have to bear the pain of what I went through to make these logic gates, but you probably saw in the sped-up version.

And you might be wondering yourself, this seems kind of inefficient. Um, you know, for everyone who ever wants to use one of these displays, they'd have to rebuild the same exact circuit themselves, which kind of sounds interesting and, uh, redundant. And you can imagine there's other times where we'd want to replicate similar behavior because what we've effectively built here is a lookup table. So, we we clearly specified here for every possible input, here is the exact output we would want. Um, and it turns out this is a very common thing and we'll actually come to it again not too long from now on our computer, that there is a chip for this.

So, I'm going to tab over here, um, and there is something called ROM, read-only memory. So, let's read the definition from Wikipedia. Read-only memory is a type of non-volatile memory used in computers and other electronic devices. Data stored in ROM cannot be electronically modified after the manufacturer of the memory device. Read-only memory is useful for storing software that is rarely changed during the life of the system. Software applications such as video games for programmable devices can be distributed as plug-in cartridges containing ROMs.

So, uh, let's not get this confused with RAM. RAM stands for random access memory. I don't actually think I explained why it's called that. Uh, RAM is called random access memory because in our implementation, we can look at any specific address in RAM just by punching in a value. So, it supports random lookups. Uh, this might seem intuitive, but earlier versions of of memory were actually sequentially accessed. So, if I, as if I read address one, I would have to read address two next, and it'd have to, uh, circle all the way back around the address space for me to be able to read address zero if I'm at address one already. So, that's where RAM comes from.

ROM, read-only memory, is pretty different. Um, the second thing that we should break down in this definition is what is non-volatile memory. So, RAM is considered volatile because when you unplug and restart your computer, RAM starts off being zeroed out or has some random values. So, the the values we put in these registers are not lock, are not persisted. You can see that if I punch in a value and then stop the computer and start the simulation again, that value is gone. Um, and I guess the, uh, analogy to your computer is if you're typing on a word document, if you command S or control S if you're on Windows to save it, that writes it to your hard drive, and that's that's stored. Until you do that, the text that you've you have pending in your editor is just sitting in RAM of your computer. And if you were to unplug it and plug it back in, you lose that data. So, you've probably seen this and dealt with the frustration before of a computer shuts down or loses power, someone trips over the cord, and you lose all of the state of your computer. And that's because all those things are stored in RAM, which is significantly faster to access than from disk, but has this trade-off of, you know, not being persistent. But I digress.

Um, so ROM is effectively a big lookup table. And something interesting about ROM is that it says it cannot be modified after the manufacturer of the memory device. So, if I actually wanted, um, to build a read-only memory for what we've built right here, I'd need to find a manufacturer for ROM and effectively send them this table, and they would manufacture a physical chip, um, that would look like this, and you would plug in your, whenever you plug in your inputs on some of these pins, it's guaranteed to to light up the correct pins on the output, which is pretty cool, but, you know, unfortunately, uh, that's kind of limited. You know, what if we accidentally made a mistake in this table, got that ROM chip, and, uh, realized that there was an issue, we'd be out of luck. You can't do anything about it. You'd have to go to the manufacturer and and get a new one. So, this is kind of inefficient.

So, what came after ROMs was called PROMs, which stands for programmable ROM. And let's read the definition from Wikipedia. It says, a PROM is a form of digital memory where the contents can be changed once after manufacturer of the device. So, basically, what this means is, uh, I mean, it's exactly what it says. You now get the ROM chip that we kind of have here, but then there's also this burner, and it lets you specify the values as you want them. So, rather than having to send that data sheet to the manufacturer, the manufacturer will just give you the ROM, and you can burn in the values yourself. But if we look back to the definition, it can say it says can be changed once after manufacturer. So, this kind of still has the same mistake. If you accidentally punch in the wrong value at a specific, for a specific input combination, your chip's useless. Um, and you'd have to throw it away and get a new one. So, that's also not optimal.

Um, so what came after that was called EPROM, stands for erasable programmable read-only memory. And so, we're not going to read this long definition, but what it is, I'll show you a picture of it. It looks very similar to the read-only memory we saw earlier, but it has this exposed element here. And it turns out that if you, uh, shine UV light onto this exposed element for enough time, usually it's like 15 or 20 minutes, it'll wipe the entire contents of the ROM, uh, out. It'll replace everything with zeros, which means you could then take a a programmer and do the same kind of burning that we had for, uh, programmable ROMs. So, this is pretty cool. Um, it now means that if we accidentally plug in a wrong value, we don't have to throw away our entire chip. We can actually, uh, just redo it ourselves. We can clear out the entire contents of the chip and then redo it ourselves, and then it's still ROM at the end of the day. So, once it's in my computer and I have it programmed, if I keep powering the computer on and off, the values in this lookup table will still exist. So, that's cool, but, um, it turns out that's still suboptimal. As I just said, it takes 15 to 20 minutes, I think, uh, to clear out these errors. It also requires you to pull it out of your computer, which is not ideal.

So, the the latest thing we have, um, is called an EEPROM. Stands for electronically erasable programmable read-only memory. So, let's build up from what we have. We know what a ROM is. That's just a basic lookup table. Programmable means that we can program it ourselves using this programmer tool. Erasable means that we are now able to clear the values of it, um, if we accidentally put in a different, an incorrect value, or just want to change it for our own reasons. Perhaps you want to use it in a different computer or something. And the last thing is electronically erasable. And that means that instead of having to pull it out of your machine and expose it to UV light for 20 minutes, there's simply, uh, a line on this that if you write, if you put one on, it'll clear out the entire contents of the ROM. Um, so this is pretty useful. And it turns out, um, we're going to need this in our computer again.

So, if I come back here, then all this is to say these logic gates are functionally correct and work. But we could also just have used a, um, a some form of one of these variants of ROM, ideally probably just like an EEPROM, and, uh, program this table in, uh, using by burning the the physical values. So, I literally burn in for this specific input 000000, these would be the outputs that the ROM should output. Now, I do that for all of the, uh, 10 different values. And that way, our wiring would be a lot easier. Instead of having all this right here, decoders, uh, feeding into all this mess of logic gates, we'd have the outputs here feeding into a ROM chip, and then the outputs of the ROM chip would just feed directly into the seven-segment display. So, that's pretty cool. Um, and that's all we'll talk about for ROMs for now, but hold on to what we just learned because it turns out ROMs are going to be the the glue that irons this computer together and lets us go from the human having to punch specific control lines to the computer knowing what it should do when based on some predetermined human instruction that exists somewhere in the computer's, uh, computer's mind.

Um, so the last thing I'm going to do here is, right now, this is connected to inputs that we're just toggling manually. Um, I'm going to connect this to the bus so we can actually just see what values on the bus at any times, uh, for values that are under or equal to 9. But, uh, I will do one other thing where I'm actually, uh, going to hook that into a register. So, the issue with just displaying the values of the bus at any time is we saw that when we were moving values in between, uh, RAM and the ALU, the state of the bus is changing pretty constantly. But if we just wanted to load something from RAM into the ALU, do an operation, and then see what the result of it is on our display, uh, it'd be easier if we, uh, could only display the value that's on the bus at a particular time. So, the way we get around that is we just have our bus read in. We build a new register like we've done for the A registers here and the B register here. We just have another register, and, um, it has its own control line. So, right into the, like we could say, like the display register, and whenever we pulse that line, uh, the register will latch whatever is on the bus, and then that value will be locked into the display until the next time we change it. So, that way, even if the bus starts changing immediately and we just want to keep the value there, um, we don't have to, you know, have the user be seeing a bunch of intermediate values that are effectively nonsensical to them. And this would be pretty cool because, you know, one of the first programs we're going to write for our computer is just counting by twos. So, we'd like to see like 0, 2, 4, 6, 8. And turns out if we didn't have a way to selectively decide when we'd want to display the value on the bus to the user, uh, I guess to the human, uh, it'd be a lot of gibberish, and you would see a lot more numbers being displayed than the the counting you'd expect, even though your computer's working, but you just wouldn't really know, um, what to what to interpret versus what's a scratch value being used temporarily.

So, let me go ahead and wire that up.

Okay, so I've pulled the bus down a little further, added new a new register, 4-bit register, and, uh, the clock signal for that register traces this wire all the way here, which is now w right into the out register. So, whenever we pulse that from low to high, uh, whatever value is on the bus will get latched into this register and will be shown onto this display. And I've also prepared this by loading, uh, two values into RAM. So, at address 0, we have the value, we have the binary value 000, which is two, and then at address one, uh, we have the value 00001, which is just one. Um, so we can do, we have two and one. Uh, let's load those from RAM into the ALU and then do the arithmetic and then capture the result onto the, uh, output register and expect it to be displayed.

So, what I'll do is I will connect the RAM to the bus. Uh, let's start with address zero. So, we can see we have, uh, the value two written onto the bus. Let's write that into register A. Now, let's switch to the second address in RAM and let's write that into register B. And now we can see that we have two in this register and one in this register. And, um, that all looks good. And let's go ahead and disconnect this from the bus. And connect these two, connect the output of the ALU. So, now we can see the output of the, uh, RAM, which was doing 2 + 1 is now three. That's binary 0011. And what I'll do, oops, uh, doesn't really matter what address we're selecting on RAM. What I'll do is I'll pulse this, uh, right to our

register. So I'll set the clock input on this register from zero to one, which triggers a rising edge, which means the register will latch in the input value, which is 0011, corresponding to binary 3. And we'd hope to see that on our display. So let's go ahead and, uh, set this high. Congrats. We see three. I'll put this down low.

So, um, now let's just take this a little bit further. So we have the output of three onto the bus. Let's, let's do, uh, 3 + 1. So we have value three on the bus. Let's read that back into the reg, the A register, which has two. And I can now see four is written on the bus. That's 0100, which is binary four. So if I pulse this flag, I can now see four is written on the bus. If I do the same thing, I can keep just adding by one.

So the steps we take now that we've gotten our computer into this state is to read the output of the ALU, which is on the bus, into register A. Step one, read into register A. Step two is simply just update the out, the out register. And now we're at five. And so I can just keep doing these two things. And you'll see that the, uh, the register just keeps counting up on the on the display. And if I then disconnect the output of the ALU from the bus, you know, it doesn't affect our display. Um, it still just holds on to that, that last value. So our display is, is, is kind of stateful in a sense. It is a register, which is then connected to a read-only memory that, uh, forks into a seven-segment display. Cool.

Um, that's all we will do for now, and let's jump back to my iPad. So we're back here, and let's diagram where we left off, uh, at, at a more abstract level rather than showing specific logic gates. Um, so we can just reason at a higher level. So we have this bus, and in the demonstrations we just built, we had a 4-bit bus. Our computer, as I said earlier, is going to be an 8-bit computer. The reason I was doing four bits in the demo is you could imagine that the complexity would just increase exponentially every time you add a more, a new bit. So, you know, for each register, there'd be a lot more control lines, um, and RAM would be a lot more complicated. So the, the issue is, for the sake of time, it made more sense for me to work with four-bit buses and four-bit values, but the concepts are still the same for 8 bits. You just imagine we literally extend everything.

So all of our registers are 8 bits, and, um, we will also increase our memory addresses for RAM to four bits. But let's just, uh, start with the bus. So six, seven, eight. Okay, so we have eight lines, and, uh, this is going to be our bus. And so every component will connect to the bus from here on out. And the next thing we had was the ALU. So I'll draw that. And the inputs to the ALU were actually two registers. So we'll call this register A, and its output fed into the first operand of our ALU. And then register B was our second operand, and it, both these always just feed straight into the ALU, but then they can also read values in from the bus. So these are both connected to the bus, and, and then we had, uh, an add-subtract line. And then the output of the ALU wasn't directly connected to the bus because, recall, only one thing can be written to the bus at a time. Um, so it's actually going to be backed by something we call a tri-state buffer.

So a tri-state buffer, um, pretty much in the examples we were showing, we were using a switch. So I'd manually have to click, and it would either physically disconnect or connect, uh, each bit position of a particular component. In our example, that was either the ALU output or the RAM output to the bus. Um, rather than us having to click, uh, it'd be nice if we could just have an input signal, and that would determine if something was connected or not. So, uh, let's see here. So, the tri-state buffer is kind of denoted, let me move over here to some scratch space. It's kind of denoted like this. It's denoted like this. And I know this gets confusing because our inverter gate is denoted like this. Uh, but that, that circle kind of makes a world of difference. And we have some input A, and then we have this control line B, and then the output of that is C. So pretty much what we can say is if B is one, and there's obviously inverted versions of this, let's just say if B is high, then then C will equal A. I.e., the value of A will just flow on through. Then if B is zero, it does not mean that C is zero. It does not mean that C is one. It means that C is just disconnected from the, from the bus. So it's not an output of 01. It literally means no output, the absence of an output. And so that'll physically disconnect us in the same way that we saw in the software, um, that, uh, clicking that switch would physically disconnect the wire. So you can imagine like it's kind of the same thing we saw, um, here. This is what the software looked like. And so pretty much whenever we have B is being one, um, then when B is one, the thing will fall, and it'll let the, it'll let A connect to C. And then whenever B is zero, it'll pick this thing up, and it'll be physically disconnected, and that's how we'll guarantee that, uh, only one thing is writing to the bus at a time. And this is nice because it now adds a new toggle for us. You know, we've talked about the toggles we have for writing values into registers or putting something out on the bus. And here's a new one we have, uh, for physically connecting or disconnecting us from the bus.

So, let me go ahead and clean this up and let's add this in here. And so that means we actually have a new control line now. And we'll call this ALU out. And pretty much when this is set, the output of the ALU will be written onto the bus. And when it's not set, i.e., it's zero, it'll be physically disconnected. So I'm also going to do one other thing here is I'm going to start highlighting all of the control lines we have because we kind of have a good number of them now. So let's just, uh, keep track of this. Uh, the add-subtract one is one we have. And then we also have control lines for, um, register A in and register B in. So let me highlight those as well. Cool. So that's our ALU.

And then after we had the ALU, we went and built RAM. So we have pretty much a register that reads, uh, an address from the bus. So our bus is 8 bits. Uh, we're going to make our addressing space four bits. So even though the bus is an 8-bit bus, we will actually say that our memory addresses in our computer are all four bits. And this is a design choice. We are designing this ourselves. We actually could make them any number of bits. More bits means more address spaces, which means that your computer can have more working memory. Um, but we'll see that when we need to do an operation, we need to specify an address. And so we are going to get to a point where we need to say something like, load the address from, load the value from some address in RAM onto the bus, and we need to encode that signal onto the bus itself. So if our address was 8 bits, then there's no way that we could fit in an operation that says to read from RAM, whatever signal that may be, however we would like to encode that and the actual address. So we decide that, uh, this is just by decision that we'll say four bits are going to be for addressing, and then maybe four bits later down the road will be used for saying what we want to do with that address. Um, so yeah, so we have something we'll build a register, uh, in this register, we previously in our software representation just called it the RAM address selector. We're going to give it a bit more, uh, a slightly changed name, but the effect is still the same. We're now going to call this the memory address register. Uh, it's short for, uh, MAR is the acronym. And we can just know that it stands for memory address register. And so it is a 4-bit register. So let me actually show that a little bit better. So I will say a four up here. And all of our other registers that we've worked with so far are 8-bit registers. So let me make that clear too. And, you know, this is an 8-bit value. The output of the ALU is an 8-bit value. So it'll write to all four, uh, all eight, sorry, all eight lines of the bus. The memory address register will just read in the memory, the bits from the rightmost four address lines. So it won't actually connect to all four of the address, all eight of the bits, uh, on the bus because it's our memory addresses are only four bits. So then there's kind of a choice of like, which four bits are we going to actually use on the bus whenever some other component wants to put out a memory address for RAM to operate on. And just by design, again, we could have picked any four bits, but, uh, just by design, we're going to go with the rightmost four bits. And these are called the least significant bits. And the leftmost four bits would be the, the most significant bits or the highest significant bits. So we have our memory address register hooked in to the least four significant bits of the bus. And this is always just reading in. So, let me actually, uh, update that representation slightly so it's not ambiguous in the future because we're going to be adding several more components here, versus these two registers are both reading the full eight bits. And let me clean up this right here. Cool.

And then there's also another, uh, control signal here. You know, the, um, the, we, we're turning this into a register. It was just a selector in our original thing, but we're now making this encode the value in register. And we know that for all registers, uh, they need some control line to determine when they should read the value that's on the bus into their, uh, bit positions. So, there's a new signal called, um, we'll just call it MAR in. And let me highlight that so we can keep track of all of our signals, our control lines. And then this memory address RAM is always looking into what value is here because recall that RAM has two operations, read and write, and the only thing, uh, for both of those operations, it needs to work with a specific memory address. So you're either reading a specific memory address, or if you're writing a value in, you need to know which address you're writing that into. So RAM has will look at this memory address, uh, register to determine what to do, and then, um, it'll also need to, uh, read in from the bus directly too. So, and so RAM, when it wants to write a value onto the bus, we also know that happens. Um, it has, uh, so we're use the same sort of, uh, tri-state buffer that we talked about previously. And so the output of RAM can be written onto the bus conditionally based on whether or not this output line is set. And so we have an output line here, and we will call this one RAM out. So if it's set, RAM will write its value onto the bus. And if it's not set, then RAM will not write anything onto the bus. It won't write zeros onto the bus. Literally would be physically disconnected from the bus. And so this will be enough for reading in values. If you wanted to read in a value, uh, if you wanted to read a value from RAM, you'd put that address onto the least four significant bits. Then you'd punch this, uh, MAR in, and so it would latch it into the register. Then RAM's always looking at whatever that memory address line is, and it's trying to write the values here. And then we'd punch this RAM out, and the value would come out onto the bus. Um, and we need to make sure that in between us putting the address on the bus and us punching this RAM out, uh, whatever is writing the address onto the bus needs to stop writing it onto the bus. Or else we'd have a, uh, short circuit because two things will be writing onto the bus. The RAM would be trying to write its output onto the bus, and whatever is writing the memory address to read is writing onto the bus. So that covers reading from RAM.

Then the last thing is, uh, writing into RAM. So if we wanted to load a value into RAM or write a value into the RAM, we need to specify the address. So we'd put the address onto the bus, we latch it into the memory address register, then we'd stop putting the address onto the bus, but then we'd put the value that we want to write in at that particular address onto the bus. And so RAM needs to always be listening to what's on the bus. And it's, RAM operates in our, uh, in our actual computer. It's going to operate on 8-bit values. So I'll denote this with an eight. And so it reads all eight bits from the bus. And, uh, the only thing we then need to add was the punch button we had that would perform the write operation that we saw in our, in our circuitry. So I'll add one more signal called RAM in, and that is used to write some value into RAM. Cool.

So we, uh, started with our ALU, then we built RAM, and the last thing we just did was build this, uh, display register. So in our, our contrived example we had in the digital software, it looked at four-bit values and only outputed one number, one digit position. In reality, we're going to, uh, let, uh, this, this, uh, display display any number of values. You understand the concept. We're not going to go and reprogram that ROM, but you can, you know, we, uh, have a register that looks at the entire bus, and that's going to connect to an 8-bit register. So a register, and then I'll denote it with an eight, and we're going to call this the, uh, display register, um, or the output register. So, uh, that means that we have a corresponding signal here, a new line. Um, we'll call this display in. So display register in. So whenever that hits a rising edge from 0 to one, we will latch in whatever values on the bus. And we'll just need to be careful to make sure that there, there is a bus. And then we know from what we just built that there would be a ROM that looks at this 8-bit signal and then outputs some number of control lines. And those control lines will get consumed by several, uh, of these seven-segment displays next to each other. Pardon my bad drawings here. And tada. This is kind of what we've built, uh, on the software, uh, just conceptually laid out here.

And so let's actually now talk about, um, some of the operations our computer is capable of doing. So the first one is, let's talk about how you would load a value, um, how you would read a value from RAM. So to read a value from RAM, we have a few steps we want to take. So, uh, read from RAM. The first thing we want to do is put an address onto the bus. So in order to read a particular value, um, from RAM, we'd actually need to address it. And so we need to get that value into the memory address register. So the first thing you do, I don't know why I denoted this with a one. Um, we'll just say read from RAM. First thing you do is, uh, put the address on the bus. Then the second thing you do is, once you put the address onto the bus, um, you'd put, uh, you'd toggle MAR in. So you, you know, you'd let it go from low to high. And then the third thing you do is, at that point, uh, the RAM is always looking at this memory address register. So it'll immediately look up the value that's in that address and try to put it right here. But it's blocked on this RAM out that's disconnected. So before we can put that value of RAM out onto the bus, we need to, uh, stop writing the address onto the bus. So stop writing address onto bus. And then finally, we could then put RAM out, uh, from low to high. And at that point, we would, uh, have successfully loaded a value from RAM.

And now let's talk about how we'd write to RAM. So if you want to write to RAM, the first thing you do is you put the address that you want to write into onto the bus. So put target address on bus, and then MAR in toggle. So you want to read that into this memory address register over here. Then now that we've loaded the address, we want to stop writing the address onto the bus. It's looking pretty similar to the read so far. And now we need to put the actual value that we want to write into the address that's now captured here onto the bus. So since we've captured the address into the memory address register, it's not imperative, if it's not imperative that we keep that value on the bus, which is why how we actually free up the bus to then hold the 8-bit value that is the value that we'd like to write into that particular address stored in the MAR. So now we can say put value on bus, and then once we've done that, the only thing we need to do is pulse this RAM in signal, and that'll latch the value into the corresponding register. So RAM in would need to go from low to high, and just like that, we've, uh, written to RAM. So cool.

And so what I'd like to do now is actually delete everything we just drew over the past 10 minutes. And let's actually start getting back to the concrete part of this implementation. And what we're going to do for the remainder part of this segment of finishing off the CPU is tying things together. And it may not seem like we're done yet. And it's because we're not. We're kind of in this weird state where we have memory and an ALU, but like no way to really tie it together or understanding of like why we'd want to tie it together. Um, so up until this point, like we started off with with binary and like all of that logic clearly stacked on top of each other on top of each other until we got to the point of a register. Then when we got past the register, we kind of had to split where we like went and built this ALU, then we went and built this RAM, and then now we kind of recently tied those concepts back together. And unfortunately, to bring this all together as a whole requires us to go into some ambiguity. It can't clearly stack. There kind of has to be some amount of, uh, take this for what it's worth, and then when I can tie components back together, it'll make sense in the end. But I, I think there's a way that we can do this, uh, that minimizes the number of head-scratching that happens along the way. So, um, what we, we described some possible operations. Let's take one of those and try to build it out a little bit. So what we're going to say now is, uh, we're going to build a lot of operations, ations, commands, we can call them for our computer. And each of these commands is going to do something very small. Maybe load a value from RAM into a register, uh, can be one. And then maybe one can be, uh, doing an addition and writing that value back into RAM can be another instruction. Or maybe one instruction is taking what's in a register and writing it onto our seven-segment display. Um, and the idea is if we have these different instructions defined, and the computer knows how to implement each of those instructions, i.e., it knows actually what to do, which of these lines to punch at which time and in what order, then us as humans can create programs by stacking these instructions together, which is pretty cool.

So, what I'm going to do is, excuse me there. Um, we're going to create another register. Yes, one more. And we're going to call this the instruction register. And for now, don't worry about, uh, how a value gets into this register. But let's just say that this register, uh, tells us what we, what the, what instruction our computer should do next. And then let's suppose, and I'm going to do this actually in a different color because this is, is, is conceptual. Um, there's some part of the computer that actually looks at what's in this instruction register, and it's the brains, uh, we can think of it as the brains that will actually go and punch each of these other lines that go and do something at different times. Um, and we're going to finally make sense of how that looks like really shortly, i.e., now. So, uh, our instruction register is going to be an 8-bit register, and here's the format of the instruction register. So let's, uh, let's come over here. The instruction register, it's an 8-bit register, and we're going to split it into two components. So it'll be one, two, three, four, five, six, seven, eight. We're gonna split it down the middle. So the, the first four bits, the left four bits are going to denote the, uh, instruction. And then for some instructions, we might have an argument that we need to pass in. And so we'll use the last four bits for denoting the argument. So the first instruction we're going to build, so this is our instruction register. Our in, we're gonna build a table of instructions. And, um, basically what I'm saying is we have four bits to denote what instruction we're going to execute, which means we have two to the four different values can fit into that instruction, uh, instruction part of the instruction register, which means we have 16 different instructions. That's how many instructions we'll build up to. That's as many as our computer supports. You'd imagine if this instruction register was more than 8 bits, we could have a lot more instructions. For example, if it was a 9-bit register and we put an extra bit towards that instruction component, we could have 32, uh, 32 different instructions. For this case, we'll start with, uh, 16 different instructions. And we will talk a little bit about how this computer scales up to like more modern computers. Um, and we're going to build out up to 16 different instructions. It turns out we don't even actually need to use all of these to to get a functioning computer. Um, and then argument. So, what actually do we mean by argument? So, let's actually figure out what this means just by building our first instruction.

So, I'm going to define what our first instruction is. Our first instruction is going to be called load A, oops, LDA. Um, let's actually put this into table format. So I will say short name, full name, op code, which I'll explain in a second, and then we'll give it a description. So basically, um, instruction is synonymous with op code. And then for any instruction that has an argument, we call it the operand, or it can be also just called arg for short. You'll hear these used interchangeably. Um, so let's, let's define our, our first instruction that we're going to implement from scratch is called load A. Short name is just LDA. Its full name is just load A. These are invented by us. This is the point where we are just inventing these instructions. Different computers have different instructions, and that's something we'll also talk about and is really interesting. Our simple computer we're building right here has just enough instructions to show off the fundamentals of a computer and write non, or I guess you could say non-trivial programs, uh, that the computer can operate. Our op code, let's just give it the number one for now, 00001. And what load A does is it is going to load into the register A of our computer. Recall register A is this, uh, left-hand side of the operand, and what it's going to load into A is RAM at the address specified by the ARG. So if you've programmed before, you know those, uh, these these brackets are kind of indexing into a structure. I'm making this video for people who have not programmed before. So what the brackets just mean is it means go to whatever's left of the brackets. So that's RAM, and then this position in RAM. So it's saying pretty much whatever the argument is, if the argument is two, whatever the second value is at RAM, whatever RAM at address value two is, take that, load that from RAM, and spit it into register A. So why do we care about this instruction? Well, in order for us to addition, we're going to want a value in register A and B. So the very first thing we need to do is get a value in register A. Um, and we're going to say that that value is probably going to live somewhere in RAM. So what this instruction will do is take some value in RAM, throw it on the bus, and then register A will need to, at the right time, read in that value from the bus. And so if I throw in 01, then the four bits that we have remaining are the operand, the argument, and that's going to tell us which address from RAM we actually want to load into register A. And so I have four bits to do that. But what's really interesting is that when we designed RAM, I also said that the memory address register is going to be four bits, which means those four bits, even though the rest of our computer is centrally designed to be eight bits, those four bits are enough to fully index every spot in RAM. And so I know when I earlier I designed RAM and I said, "Hey, it's kind of arbitrary. We're making, uh, the memory addresses four bits in RAM." It actually works out perfectly because it means for all of our instructions that we build here on out that need to reference a specific address in RAM, they can do so using those four bits. So our instructions can be fully complete. Um, which is also really nice. And it, we'll see for the most part that, uh, our instructions usually, if they have operands, arguments, they're going to be addresses into memory. But that's not always the case. But, uh, it's designed around this. So there is something, it's not just coincidence that we're designing our, uh, instructions to use four bits for arguments, and then the RAM has four-bit addresses. This is not coincidence. This is very much a, a choice made with high agency. And this is again something that we designed for our own computer. So you could imagine, you know, maybe if we had a, a 20-bit, uh, bus, maybe we'd have like 10 bits, uh, could be used for the memory address register, which means our, our instructions might be 10-bit operands and then maybe four-bit instructions. Um, so there, there is something pretty cool to be said about this.

So, uh, basically, if we throw in this value, let's, let's try to consider an actual value. If we throw into the instruction register the value 01010, um, a few hours ago, this would have looked like nonsense to you. Uh, maybe one hour ago, you would be able to derive the number out of this, and now we're actually saying, hey, this, this isn't just a number in binary that we want to convert to decimal. There's more to it than this. This is actually, first off, it's, it's two different numbers, and the two numbers are not just one and two. Uh, there's actually, it's an instruction. We're saying execute some instruction whose ID is one, and that instruction takes an argument, and the value to that argument is two. So if I come back over here, uh, to our scratch space, um, I have 00001010, which was what I talked about. So this means load A. We're saying load a value at this address in RAM into register A, and this is address two, 0, 1, 2, however you want to denote that third index position, or just two, um, if you want to convert that from a binary number back to a decimal number.

So, let's go ahead and see the exact specific steps we need to make this instruction happen. So, I'm going to go a little bit slow here. You might be able to figure this out faster on your own, but the first thing we're going to want to do is get this 0010 and look up whatever value there is in RAM. So this instruction register has the values that we are interested in. And so in order for us to get it to the memory address register, this instruction register actually has to be able to write its value onto RAM. So it can do that. And I will denote that here. There's something interesting. Um, it only needs to write those right four bits out. It only, it only needs to write its argument onto the bus. It does not need to write all eight bits onto the bus. Because the, uh, the left four bits are the operation code, the op code of the instruction that we're trying to, uh, in, uh, that we're hoping the computer will execute. And the control is the only part of this computer that makes sense of the op code, the instruction code. The only, the control part of our computer, which for now is just us as a human brain. It's our, we are the control of the computer. Um, we care about that op code because it tells us what we should be doing. No other part of the computer cares about it. So, uh, when the instruction register writes its value onto the bus, it only would ever need to write the address onto the bus. And you can kind of see that motivated in the case here where if we have this, uh, 00001010, we only need these to end up in the memory address register. So, uh, that's why we will have that, and that'll actually be a new signal, um, and we will call that, uh, instruction register out.

So assuming, uh, let's say our steps to implement this, let's, let's talk this out very clearly. So our, our step zero and slash our assumption, um, is that we are, we are assuming the instruction register has the right command in it. So we aren't going to worry about how this 000010010 got into the instruction register yet. We'll get there in a bit. Um, let's just assume for now that we, some human came and punched that value into the instruction register. So that's our assumption. So now let's actually walk through the specific steps. So the first thing we need to do is put the instruction register argument onto the bus at 0010. So we'd set instruction register out must equal one. And then after that, after that instruction register out is set to one, the value of the argument 0010 will be on the bus, and we need to let these, this MAR in line go from 0 to one. So it's everything we'll assume is zero. We want that MAR in line to go from zero to one. And what that'll do is, uh, latch in the, uh, the value, um, from the bus into RAM. So we'd say MAR in goes to one. So it's, it's interesting because there's a strict ordering requirement here. Um, the instruction register has to put its value onto the bus before the memory address register can read it in. And that might seem like a trivial thing, but this is actually really important, and we're going to have to make sure that we're very careful about that. In general, uh, we've talked about this already. It seems trivial, but I'll restate it again because I think it can't be understated. Uh, if something wants to read a value from the bus, then the component that it's reading the value from has to have that, have to have, has to have its value already written onto the bus, uh, before the another component can read it in. Um, so we, we kind of view this ideally, this is atomic. In reality, it has to be sequential. And so ideally, we'd say, hey, at the same time that we write the instruction register's on its value onto the bus, the memory address register to read it in. Um, and that's how we'd like to think about this. That's how we'd like to think of putting a value from one component to another. Uh, in reality, we know we'll have to do it sequentially. And so we'll also come back. I'm going to leave this written on the screen. Um, and I'll also highlight it so we don't forget to come back to it in a timely manner.

So once that happens, the value from RAM is in. So then what I can do is we can say, okay, well, now the value, uh, from the instruction register, well, the instruction register out and the MAR in are both not necessary anymore. So they can go back to zero. We can reset those components back to what they were. And so this means nothing's writing onto the bus. Um, and it means we've, we've loaded our value. Uh, the 0010 has made its way into the memory address register. And what that means is that RAM has looked up that value because RAM is always looking at what's in the contents of the memory address register, and it has the output right here. So then what we'd like to do is write that value onto the bus. And then to get it into register A, we can use our register A in line. So we'd like to transport the value from RAM onto the bus into register A. So the two control lines we use to do that are RAM out, RAM out will put the value onto the bus, and then after the value is written onto the bus, register A can read it in. So I will say RAM out and then register, register A in. So RAM out equals 1 and register A equals 1. And then we kind of the same thing where ideally these are atomic. Um, but it's important because the moment we set this RAM out line, it connects it to the bus, to the bus, and its values will be on the bus, and then only based on what we know about registers, only when we set A in from low to high, only at the exact moment that rising edge happens are we actually going to latch in a value to register A. So once that's done, the value, uh, that we wanted to get into register A is done. And so we've kind of fulfilled this contract right here. Register A now equals whatever was in RAM at the address specified by the argument to the instruction, which in our hypothetical example is, uh, 0010. And so once that's done, I can now say, uh, we can reset both those lines as well.

Okay. So, uh, this is pretty interesting. Um, that doesn't seem that complicated, but let's look at it at a slightly different view. Uh, where instead of listing it out in a series of steps, let's, um, look at it in terms of clock edges. So what I want to do is we said, um, we can have all the signals we used here. So IR out, MAR in, then RAM out, and register A in. And each of these starts off at low. And then to execute the instructions, they said the first thing that needs to happen is instruction register needs to write its value out. So it needs to go from zero to one, and then at some point after, uh, it goes from one, uh, this memory address register can also go from zero to one. And because this is after this, we know that the value on the bus will be correct. And then we said, okay, now that that's done, uh, both of these values can, can kind of at the same time, we can reset them to zero, and that continues. And then the whole time this register, this RAM out and A in lines are off. And then now that the value, uh, is the address has been loaded into MAR, we, we can, we know the value is looked up in RAM. So we wanted to get the value from RAM's output into register A. So what we did was we pulsed on this RAM out, kept it up, and then at some point shortly after that, we can, uh, punch register A in, and that'll latch in the value. And then, uh, once that was done, our operation was done, so we just reset both these lines to zero. And I can carry these because these top two lines, nothing changes. So you can kind of see like there's, there's, uh, two timing signals of interest here, um, and in order for, like, this represents a transaction of information from one component to another via the bus, and this represents another transaction of information from one component to another via the bus. And what we'll find, I'll spill this out, is as we build more of these instructions, a lot of the implementation is going to just be moving data from one component to another using the bus.

So, what actually turns out happens is we're going to introduce another component to all of this called the clock. And I'm going to draw the clock up here. And basically, what the clock is doing, it's a physical, uh, component to the computer. And it's, uh, you don't need to worry about how it's built, how it's built, but at a fixed rate, it'll just keep going from 0 to 1, back to zero. And this is pretty cool. I'm not drawing this, so it's fixed rate, but, uh, ideally, this is a fixed rate. And the same way every component's kind of hooked in, uh, to the bus, uh, the clock is also pretty central to the computer, even though I've draw, I've drawn it a little bit a little far out here. Um, but basically, what we saw here is, uh, is, is something similar to this. We had components, you know, we had a, a zero to a one here, and then one to zero here, and then a zero to one of interest here, and a zero to one of interest here. So, uh, let's see how we can actually use the clock to, um, aid in some of what we just did manually.

So, it turns out there's something slightly interesting about what we did here, and that when you're writing a value onto the bus, you can do it whenever because we're kind of making this guarantee that when we start, nothing is writing onto the bus. And then we're also making a guarantee that like when we are done writing onto the bus, we stop writing before we start putting the next thing on. There's clearly this non-zero gap here. So to write a value onto the bus is safe. To read a value in from the bus is when things get tricky because we want to make sure the value is written out onto the bus before. So pretty much this clock here. And then the other thing is when we do need to read in, we can only read in on these rising clock edges. So, uh, what happens is, you know, when the clock is low, we can put in, we can put the value out on the bus any time from here to here. Let's say like from here to like right before anytime here, it's fair game to read out to the bus. And then at the exact moment we go from 0 to 1, we want to feed in. But, um, we can take this a step further and actually say, well, it'd be nice to just throw the in signal and the out signal at the same time. Uh, because that's kind of what we want to do. We know we want to write from component A out to onto the bus and then have some component B latch that value in. So, uh, but, you know, the issue is we can't do that at the exact same time because of the issue we described. You know, there's, uh, it's unclear if the value would be on the bus at the exact time that the register latches it in. But if we actually, uh, let's take the example of this MAR in, if we actually and this signal with the clock, and let that be the signal that goes into the register, then it turns out we can throw both these values. So we can throw both, um, the out and the in to both equal one here. And so the out still goes onto the bus. The value goes onto the bus totally fine. In our in our case, that was, um, the instruction register, its last for this 000 goes out to the bus just fine. And the in, because it's ended with, uh, this, this clock signal, stays as a zero. And that stays as a zero until the exact moment we hit this rising edge. And at that point, this input, both inputs of this AND gate become a one. And so we latch in at this exact moment, the, uh, the rising, um, signal. We latch in the exact value that's on the bus. So we've accomplished what we want. So then now when we're up here, uh, we can just, you know, be sure that we, uh, unset these signals. So we can, you know, make sure that we put both them back to zero. And then when we get down here, we can do the same thing for, uh, RAM out and register A in. And we could set both of these to one. So out and in, RAM out and register A in can both equal one. And as long as we have register A's in signal anded with the clock, then we can take advantage of the same trick. So let me go ahead and for all of our in signals, let me go ahead and AND them with the clock so that we can make sure that's apparent for the rest of this.

Okay, so I've gone ahead and for each of our in signals, I've ended them with the clock. So for our memory address register reading into RAM, reading into the A register, reading into the B register, or reading into the display register, and all of these are now ended with the clock. So what this means is our clock signal, uh, we can also pay attention to that in our control brains, and us as humans, as we're punching these lines, we can kind of do is react to the fact that the clock is going up and down and being sure that we set lines appropriately. So if I jump back to our original example here of how we constructed this load A operation. Let's say we have our clock, and it's just always going from low to high. Then basically, what needs to happen is while the clock is low, we need to set IR out equals to one. Let me, and MAR in equal to one. And then we aren't changing the clock. The clock just exists and changes its value on its own. But at some point, the clock will go from zero to one. And that'll have the effect of actually latching in the value into the memory address register because the, the line for the memory address register in was one. But because we're adding it with the clock, the actual input that doesn't that goes to the register doesn't actually hit that rising edge until the clock hits a rising edge, which is pretty neat. And then when the clock is high, we can pretty much set these things back to zero. And [snorts] then when the clock falls low again, we can kind of reset and prepare our next signals, which was RAM out equals 1 and A in equals 1. And then the next moment we have this rising clock edge, it'll latch the value from RAM that's written onto the bus into the A register. And so then when that we're at the rising clock signal, and I guess for just indefinitely, we can reset all of our signals back to zero. So instruction register out, or sorry, RAM out equals zero and A in equals zero. So this is cool because now what it kind of means is our control here is just going to be listening to this clock signal, and it's going to need to, for every instruction, set various control lines right before or right after a rising or falling clock edge. And this is convenient because it means the, uh, speed of the computer is now bound to the clock. So you can kind of see

For this load A instruction, we needed two clock cycles. Clock cycle meaning we needed to go from low to high, back to low, to high. So we hit this like low-high cycle, uh, alternation two times, and that's enough to actually implement the entire instruction. So that's pretty cool.

Um, before we go ahead and extend this to our second instruction, let's actually take this one step further. And, uh, one thing I've left ambiguous until now is how we get this instruction into the instruction register. And there's something interesting to be said about the fact that our instructions are all eight bits, because that goes hand-in-hand with everything else. You know, all of our operands, the ALU are 8 bits, the output register takes an 8-bit value, the bus itself is 8 bits, and, uh, interestingly, each value in RAM is 8 bits. So what we actually do, um, is store the instruction itself in RAM and then read that from RAM into the instruction register. And basically, the way our computer will execute is it'll look, when we power it on, it'll look at whatever is in address zero of RAM and treat that not as a number or a value, but rather as an instruction. And it'll load that value from RAM into this instruction register, and then the computer, the control branch that we still have left ambiguous, will go ahead and actually execute that instruction. And once that instruction is fully done, we'll then look at the next index in RAM. So we start with the first item in RAM, treat that 8-bit value as an instruction, execute it, and then look at the second item in RAM, treat that as an 8-bit instruction, and execute it.

So, in order to keep track of where we are in our execution process, we're going to have a new instruction, a new register called the program counter. So, I, I've extended the bus a little bit, and recall that our addresses to RAM are all four bits. So, uh, that means we can only index using the least four significant bits here. And we're going to have a new register called the program counter, and that is a 4-bit register. And there's also going to be, uh, so I guess it can put its value onto the bus, and we will call that signal, um, PC out. So this program counter is going to start off as zero, and it's going to point us to the first item in RAM. And then once we execute that instruction, we'd like to increment this program counter to become one. And once we execute, once we increment to to be one, then, uh, we'll look up whatever is in that address at one in RAM, treat that as an instruction, get it into our instruction register, and then execute it. And once we do that, we've executed the, uh, instructions at address zero and at address one. So we'll increment this program counter again to two. And we'll do the same thing. And so basically, this program counter, um, is going to be incrementing. It's when it should be counting up from zero. And you might be wondering how we do that. You know, this is just a register on itself. But, uh, we actually talked about this earlier when we constructed our ALU. We showed how you could, uh, if you loaded some value into the left operand and then a fixed value of one into the second operand, and the output will always be the, the operand plus one. And so you can kind of feed that output and read that back into register A, and it'll keep incrementing register A every time you latch in a new value because we fixed the value of register B to be one. The output of the ALU will always be A + one. So that's one way you can, uh, implement this counter. It turns out in an actual computer, it's not really, uh, pragmatic. There's a faster way, uh, faster meaning fewer logic gates, to, uh, build out a, a counter. We're not going to deal with that for the sake of this video because I don't think the complexity justifies the divergence here. But let's just say you already know how to build this counter. So we're going to suppose that this counter mechanism already exists. And I'm going to denote that, uh, with a better circle, and we're going to call this like a plus one. You can imagine that could be a whole ALU that takes the, whatever, whatever values in the program counter, adds one to it as a fixed second operand, and then feeds that back in. And we're going to have this same, um, kind of program counter in signal that'll kind of read in. And we can also go ahead and end it with the clock because we've done that for all of our other signals. So I'll say, so now we have two new signals.

But now what happens is we need to think about, we know what happens, uh, for this load A instruction we've designed. We know what happens, uh, in terms of what the control logic needs to do once that operation command is in the instruction register. But now we need to take a few steps back and actually figure out how we get this instruction from RAM into the instruction register. So we know that there's a value in the program counter at any given time. And so what we'd like to do is look up, treat that as an address in RAM, look up that value from RAM and get it into the instruction register. And since everything's hooked into the bus, you might be able to guess already what we do here. The first thing we'd like to do is program counter out. So read that onto the bus. Push that onto the [snorts] bus. And then also pulse, uh, or set memory address register in. And then at the exact moment we have a rising clock edge, because we've added the M in signal with the clock, uh, the value on the bus, which will be the program counter address, will get locked into memory address register. So that's our first clock cycle. Then our second clock cycle, we'd like to take the value that's in that address at RAM, which is here, because RAM, RAM is always looking up the value that's in the memory address register, put that onto the bus. So we'd set RAM out, and then to read it into the instruction register, we'd actually need a new line, uh, a new mechanism that can read from the bus into this instruction register. So we're going to hook in the instruction register to the bus, and we are going to, uh, kind of have that be denoted, uh, accordingly. And that means we have a new line that we care about, which is, uh, instruction register in. And we're obviously going to end that with the clock because we've done that for all of our input signals so far. Cool. So basically, uh, we just need to add two more clock cycles here. One is to get the value from the program counter out and read it into the memory address register. That takes one clock cycle. And then the second clock cycle is putting the value from RAM out onto the bus and reading it into the instruction register.

So we can come back to our original diagram here. And this we know is what happens once we have a value in the instruction register. But we're interested in, uh, the full steps of equations of how we get the value into the instruction register. So what we do is we set the program counter out and M in to both be one. So PC out equals 1. M in equals 1. Then we'll do that, you know, at some point here. Hold that value. Hold those two. And then on the rising clock edge, uh, that'll have the effect of moving the value in the program counter into the memory address register. And so then we're looking up the, the RAM is always looking at the MAR. And so we have the value at that address ready. So we'll put that value onto the bus with RAM out and read it in with this instruction register in. And then as soon as there's that rising clock edge, we will then have the value, uh, latched in the instruction register. And then we can actually start the execution of the load A instruction that we've designed here. So we can literally just connect these two. And so this is the full timing sequence of how we implemented that instruction. And so you can kind of see that this takes one, two, three, four, four clock cycles. Four clock cycles to implement this instruction. And it turns out, um, that is also something that we will design. It'll be a design choice. We are going to give all of our instructions five clock cycles to execute. And that is because we will see that the longest of the instructions that we design, the longest instruction takes five clock cycles, and so we need to cater to that longest instruction. There are some computers that could have variable length clock cycles per instruction. For us, it becomes easier to understand and reason about if we just say every five clock cycles is synonymous with the computer having executed one instruction. So for this, uh, command, we've used four clock cycles. This last clock cycle would just be wasted. Like it'd be a no operation, no wasted. And that's fine. It's trivial. Um, but it also turns out, we'll talk about this later, but more modern computers can actually execute, uh, entire instructions in a single clock cycle. And it turns out, uh, that you also, you would think, hey, if we just, uh, turn up the clock frequency. So right now we have this, if we just made the clock go from high to low faster, that we could, uh, actually, you know, we could just crank that the width of those intervals and have them approach zero, and that would let our computer execute instructions faster and faster, and, you know, that give the the illusion of it being just as fast as if every instruction had used one clock cycle. But it turns out you can't actually push these to zero because, uh, there's a delay here. There's a delay between everything you, you the line you set, and then it actually being received. So every time I say like this instruction, like program counter out, uh, there's actually a slight delay in the logic gates, like, uh, in the logic gates, like physically connecting the program counter to the bus has a, a delay. It's a very small delay, uh, but it turns out you have to wait for the longest delay of all components before you can pulse that clock again. So something like the ALU, where if we put a value in register A and B, there's a lot of logic gates in the ALU. You kind of have to wait for, if each logic gate takes like, uh, a millisecond, we have 50 in the slowest route, um, then you have to wait 50 milliseconds for the output of the ALU to be considered valid, which means your clock cycle, if you have something that depends on the result of the ALU output, has to be at least 50 milliseconds. So we can crank these pretty far, and it appears that the computer runs fast, but there is a true limitation. And it also turns out modern computers have that clock running really, really quickly.

So we built the first, uh, implementation of load A, but we've actually forgot one subtle thing, and that once this load A operation is done, we will correctly have the value, uh, denoted in the argument part of the instruction in register A. But our program counter is still going to be pulsed at zero, which means if we repeat the same process, we're going to execute the same instruction. What we'd like to do is actually increment the program counter so that when we repeat these same set of instructions to get the value from the program counter, uh, stored at RAM into the instruction register, we have the next instruction, not the same one. So there's one subtle thing, and that there's this program counter increment flag, uh, that'll effectively increment it. And once we use the, uh, we only use the program counter value at this very first step. So actually, at any other step along here, between here to the next instruction, we can just pulse that flag on any of the rising edges, and it'll have the effect of incrementing the program counter so that when we get to the next instruction, it's already ready. So I could just pick any, uh, any of these rising clock edges to do this and say, you know, program counter inc, uh, equals 1. And, uh, I'll also call this, I will enable this program counter increment, uh, because it turns out we'll eventually want to be able to read actually a value into the program counter directly, and that'll be called program counter in. So I don't want to get this confused with, uh, being able to increment the program counter.

So what we're going to go ahead and do now is actually define all of the remaining instructions from this computer, discuss them at a high level, and then after we do that, we'll finish out by tying together what this actual control brains is. And once we have that done, we've, uh, completed the computer, which is a crazy thing to say. So, we're not quite there yet. Let's keep going.

Um, so our second instruction is going to be called add. And, uh, the full name is also just kind of addition. Uh, this is just for our, our readability here. The op code will be two. The next number, and what add will do, it's slightly different. You know, we've, we've done addition in the ALU, and you kind of know how that works, and how you kind of punch a value onto the bus, hook it into some registers, and, uh, kind of latch that value in. But what add does is it says register A will equal whatever is in register A plus RAM at the arg specified. So there is an argument to load A. So if I, uh, call load A with, uh, address 3 as the argument, it'll take it'll go to RAM. It'll say, "Hey, whatever is in address 3, look it up, put it in register B, then take the output of that and feed it back into register A." And that will have the effect of adding whatever is in RAM at the specified argument into, uh, back into register A. So it'll be A equals A plus, uh, whatever we put in B, and what we put in B is that, that address and RAM. Okay. So that's how we do addition.

Then you'd imagine, uh, the logical equivalent to that is subtraction. So sub, and you could probably guess its op code is whatever comes next, which is three. And you could also probably guess that the effect is register A equals register A. So we take, we're always operating on whatever is in register A, and we'll subtract whatever is in RAM at arg. So, it's the exact same thing we've done before, except, uh, when we actually get the result of the ALU, we'll punch this add subtract line. When we set it to a one, uh, as we learned earlier in this video, it'll have the effect of doing subtraction.

Our next instruction is called STA, and that stands for store A. And this has the op code of 0100. That's four in, in decimal. And what store A does is it lets us take the value that, uh, is in A and write it into RAM. So we, we talked a lot about reading from RAM, but, uh, writing into RAM is also important. And the register A is kind of the design of our computer here. We actually don't have any, uh, commands in the default instruction set that let you specifically do something with register B. Everything that is done with register B is usually implicitly defined as part of one of these operations that works from register A. That's just by design. We could totally have these equivalent arguments for, we could have, you know, for this add, we could have A add B, which is the same, same operation but for register B. So it'd be like register B equals register B plus some argument into RAM. We just don't have that. Uh, and, you know, we actually could easily build it, and that's something, uh, you could leave as an exercise to you afterwards, but I digress. Store A, uh, it'll say RAM at whatever argument you specify, it will treat that argument as an address, equals whatever is in register A. So to implement this one, what would happen is once we get the instruction in the instruction register, we put the least four significant bits on the bus, that op, that memory address, and we could hook that into the memory address register. And then what we need to do is write register A, uh, have a way for writing register A's value out onto the bus, and then we can read that value by pulsing, uh, RAM in. And since we've already loaded the address that we want to write into into the memory address register, uh, the moment we pulse that RAM in and have a rising clock edge, it'll lock the value from register A into the correct, uh, component on the bus. And so you might be noticing, hey, we don't have a way for to actually write register A or B onto the bus. So, uh, we'll go ahead and and do that. So, we could do two. And so we can call that, uh, A out. And then we can do the same thing if we needed to for B. And this is the, the power, you know, this is the power of the bus. We can just decide to connect things, and it's just as easy as connecting them versus for if we had to connect it to every other component, you know, we'd have to connect it to the, the RAM in signal and then, or it with a bunch of other things that already connected to the RAM in signal. So the bus really makes things a lot easier here. Okay, so that's store A.

The next is called LDI. That stands for load immediate, and its op code is, you could probably guess, 4 + 1 is five. And [snorts] this one's a little bit different. So up until now, every argument here has, every instruction has had an argument, which is interesting in itself. Uh, we will see that that's not always the case. But, uh, whenever there has been an argument, it's been an address into RAM. This time the argument will actually be treated as a literal number. And what it'll do is it'll load whatever the argument is into register A. So this contrasts well with our very first command, our very first instruction, load A. And you can see the difference here is load A will take the argument and interpret it as an address in memory and go look up whatever is in that address of memory in RAM and feed that into register A, versus load immediate will just take whatever the argument is, interpret it as a number itself, and load that into RAM. So if I had load immediate with, uh, 011, this will load the immediate 011 into register A, which means register A will have the value of 1 + 2 + 4, which is 7. And it does mean that load A, the, you can only put in a value that's representable in four bits. So the, the biggest value you could put in is 1111, which would be 1 + 2 + 4 + 8. 8 + 4 is 12 + 2 is 14 + 1's 15. So any number 0 through 15 you can load in immediately, uh, to register A. And so why would we want to do this? Is because let's say I want to load the value five into register A. If we just had load A, we'd have to waste two instructions. We have to waste two of our slots in RAM. We'd have to waste one of them to house the load A instruction, and then the argument to the load A instruction would point to a different spot in RAM, which would house a literal value five. So this uses two spots in RAM to load a value, uh, to load a value into register A. But with a load immediate, we could just do it with one. And RAM is a constrained resource here. So we only have, uh, four addresses. So we have two to the four, um, like 16 different spots in RAM, which is not a lot to work with. So we want to use it as efficiently as possible. So that's why we have this. So that's a little bit different. And so now we've seen, uh, four examples where the ARG is a data address in RAM. Now we've seen one where arg is a literal. There's a literal number. And well, let's see what comes next.

The next instruction is called JC. That means jump if carry. And here's our op code for it. Oh, sorry. I jumped ahead of myself here. Next instruction is called JMP for jump. It just stands for jump. And this is an interesting one. What this says is all it'll do is set the program counter equal to the argument. So this is super interesting, and it might not seem that crazy at first, but recall our program counter starts at zero and then goes to one and goes to two. And pretty much it tells us, uh, what instruction, what position in RAM we should look at to figure out what the next instruction our computer should execute is. And this has the effect of just walking down RAM top to bottom. But what jump lets you do is it lets you jump back to a, a start. So let's say my RAM had some value. Uh, let's say like my RAM was organized. So at address zero, we had a load immediate three. And then we had an add, uh, add, uh, we could address six. And then at address six and RAM, we had the the literal value like one. Then what would happen is our computer would, uh, load an immediate three into register A, and then add the value one to it, so it'd have the value four. And if we wanted to keep doing this over and over, we'd have to keep adding, uh, the same add command over and over in RAM. Uh, and what we'd find is that we could only do it, uh, oh, so many times before we run out of space and RAM. But what's kind of neat here is if I have a jump command back to address one, then when, when our RAM finishes this first add instruction, it'll then the program counter will increment from one to two. We'll get here. We'll see that the value in RAM address 2, its interpretable value says jump back to address one. And so it'll reset the program counter back to one. And so our PC will now point back to one. And then we execute the next instruction, and we'll load the value address one into the instruction register. And that value is the operation to add, uh, whatever's at address six back to the register. And so this would just increment the A register by one again. And then we do that, come back here, and we kind of keep bouncing in this loop. Um, and so our program would kind of never finish. And the value in the A register would just keep increasing by one, and it, it just be counting up, which is pretty interesting. So jump lets you change the fundamental control execution scheme of your computer.

Okay, we can take jump a little further. Uh, I'm actually going to, I'm going to go ahead and erase this, and I will clean this up here. And we have four more instructions left to build out. The first, we have two more jump related instructions. JC, which stands for jump if carry, and the op code is, as you could guess, 011. And what this says is if the last result, if the last operation that happened in the ALU, uh, carried, i.e., there's that overflow, then we can jump to a specific address in memory, otherwise you go on. So if carry flag equals 1, PC equals arg. No, and when we talked about our ALU a long time ago, we built this by chaining a bunch of, uh, full adders together, and the carry out of one adder became the carry in of another adder. But then recall for the leftmost adder, there was a carry out flag, and if that flag was a one, it meant we overflowed, meaning we couldn't fit the value into eight bits. And so we've kind of ignored that in our ALU here. But what we can actually do is just, uh, build a, build a new register that, uh, looks at this carry flag. Um, so it can take the, uh, it can be called the flags register, and it'll whenever we do an ALU operation, we'll look and say, "Hey, did this last carry, did the last, the leftmost full adder carry out?" And if it did, then we know that the last arithmetic operation that happened in the ALU overflowed, assuming we're working with positive numbers. We'll just keep it simple for now. And if it did, we should latch that value into this flags register. So, what I'll do over here is I'll have a flags register, and it's going to be two bits. And what we'll need to do is also add a new control line for flags in. So this will read, uh, it'll interpret whatever values the state of the ALU and, and, and latch that value in. And of course, I need to end that with the clock. So why is this two bits if, uh, we encode if the carry out is one bit? Well, we'll see when we come back to the next instruction. But, uh, the other thing that's interesting to know is if the, uh, output of the ALU is zero. So we'll have one flag for measuring if the ALU carried, uh, if there was overflow carry out, I guess. And then one flag for measuring if the last ALU operation was a zero. And you can detect if the last ALU operation was a zero by looking at all the output registers and, uh, saying that they are all zero. So you would invert each one and then add them all together. So the, each bit position, like bit position one not, and bit position two not, and bit position three not, and so on and so on. So you'd assert that they're all zero. Uh, so you could invert all of those and add them together, and that would pretty much be your, your zero flag. I won't show that logic here because I'm trying to avoid drawing individual logic gates. But let's see why this jump carry command might be useful. So in our original example we have here, um, we started with the the number three. I guess if we looked at the state of the A register, it'd be three, and then four, and five, and six, so on. And then eventually, because our register is eight bits, we'd, uh, we'd get to the maximum value that we can store in 8 bits. So 2 to the 8, let me use my calculator right here. 2 to the 8 is 256, which means we can store values 0 through 255, assuming we're just looking at positive numbers only. But let's say we are for now. So, uh, your computer were to get to 250, and then 251, 252, 253, 254, 255. And if we tried to add the number one to it again, we have the binary. This is what 255 looks like in binary. If we tried to add one to it, what actually happens is pretty interesting where you can kind of see that it'll roll all the way back to zero, and then we'll have carried out. So, uh, if we let this keep running this program, what happens is we'd start at three, count to 255, and then go back to zero and keep counting from zero, back up to one, to two, to three, to four, all the way back up to 255. So, pretty much what happen is we just keep counting 255 and then resetting to zero. Maybe you, once you hit 255, you don't actually want to, uh, count any further. So, uh, we could restructure this program and say, um, what I'll do here is we could say if, once you, every time you do an addition, if you carried, uh, then maybe you could jump to like address 10 or somewhere further away in memory. Um, otherwise, you would jump back to address one and keep doing another arithmetic. Um, and so that way, you know, every time you do an addition, you don't try to do another one right away by jumping back to that same add operation. You check, hey, did the last result overflow? If it did, we can stop counting, we're at 255, and end the program by jumping somewhere else in memory. So that's just a little bit of motivation for that. And I said we, uh, added two flags to our register because we wanted to know if you could carry out. We also wanted to know if the last ALU result was a zero. So we'll go ahead and build that out too. And that's going to be called JZ. That means jump if zero. So, uh, that's going to have the op code of 100. And it pretty much says if the zero flag equals 1, then the program counter can equal the argument, i.e., we jump to a new address. Otherwise, we don't do anything. And, uh, well, you kind of already know how that one works. It's the same thing except, uh, you know, we need to look at the value in the, uh, the flags, uh, the flags register. So, you know, the first bit position is for carry, and you could say the second bit position is for zero. So we just need to make sure we're looking at the right one.

Okay. Our next instruction, you might have noticed, is we've now inter, we have instructions to interface with every part of this computer except for one, and that's the display that we talked about just, uh, just fairly recently. So let's have an instruction to actually write, uh, whatever value is in the A register, since that's so critical to our computer, um, onto the bus and then latch that into the output register. So we're going to call this command OUT. It's just be display. Uh, they're synonymous here. It's op code. Uh, we'll just jump around here. We can give it whatever. Let's just, uh, throw it 111 arbitrarily. We can kind of choose what our operation codes are. We've been sequential up to this point, but there's no harm in using the address space however we'd like, or sorry, using that four-bit space however we'd like to define our instructions. And so if we say formally what the, uh, OUT command does, it's going to set our output register equal to register A, which will then have the effect of displaying whatever is in register A onto this seven-segment display because the way we designed that read-only memory was to just look at whatever is in this, uh, display register. And so you can imagine to implement this command is pretty straightforward. You just put the value of register A onto the bus with A out. And at the same time, you'd have display in. And since display in ends with the clock, as is every in signal, once you have a rising clock edge, it'll hook the value into that register. And then ROM is just a constant lookup table. So it's always just going to be looking up whatever is, it's always going to be reacting to what's in the register. It'll look up. It'll say, "Hey, this value is on the register. Like, let's just display it on the screen."

And last but not least is called HALT. We'll give it op code 1111. And what HALT will do is it'll physically stop the computer. So if the computer sees a HALT signal, if the, if we, uh, have some address in our program counter, we look up whatever is in that address in RAM, put that in the instruction register, and our control brain sees that it's a HALT, it'll stop. It literally will just break, like it, the computer will not execute anything further. Um, and that'll be the end of execution here.

So these are all the instructions our toy computer has. And what's, uh, a few things to of of note here. So we saw that for the first few arguments, we, for the first few instructions we built out, there were all arguments. The arguments were all data addresses in RAM. Then we saw an instruction who had an argument, but the argument was a literal number. And then for the three jump instructions, the argument was an instruction address, but the instruction address also lived in RAM. And so there's something interesting to be said that RAM has both our data and our instructions. And the only, like, the computer doesn't really care which is which. It's strictly just going to do what you tell it to do. So you could actually write, uh, an instruction in one position. Uh, let's say if I wrote an instruction, uh, at address 4 in RAM, and then if I called load A on address 4, then it would still work. It would interpret whatever the value of the address is as a literal for the load A. But then when we're our program counter equals that address, it treats this instruction. So it's pretty cool that, uh, it might be weird to wrap your head around, but conceptually values in RAM can be both literals, data literals, or instructions. It just depends on the context of how it's, how that value is being accessed. Whenever that value is being accessed through the program counter or one of these, yeah, through program counter, it's definitely going to be treated as an instruction. But then in a lot of these other contexts, if it's like an argument to an instruction, it's going to be treated as a, a literal number, which is pretty cool. And then we saw down here that there is no argument for our final two instructions. So those write four bits are actually kind of wasteless. You could set them whatever you want. Another thing to note is we have four bits of our op code. So that should be 16 possible different instructions. But if I count out what I have here, I have 1, 2, 3, 4, 5, 6, 7, 8. I have 10 different instructions. So we are not using our instruction space fully. So we could define more instructions. It turns out this set of instructions is nice because it lets us, uh, kind of define simple enough pro, like complete enough programs on its own. But, you know, we talked about very earlier, like, hey, like our load A, add, and subtract all simply operate on register A. Maybe I could use some of those extra op codes to build load B or add B or subtract B instructions. Similarly, our OUT command will only put whatever is in register A onto the seven-segment display. Maybe I want a way of having, uh, an an OUT for B. Uh, and you could imagine extending this computer in ways on your own. You could have a second output display, and that second output display could have its own command where you could write in the value of register B to that, uh, display based on, you know, whatever the argument is. Uh, so there, there's different ways you can extend this.

So now we've defined our instructions. Um, we walked through load A in great detail, and we'll do that for some of the others. But the last thing we need to do here is tie it together with this control brains. And it turns out we know everything we need to tie this computer together and explain how this control logic works. The very last thing I'll do that I will spill out to make it a little bit easier. Well, obviously because I'm going to explain. But [clears throat] um, we discussed this instruction. The very last one we discussed was HALT. And what HALT should do is it should stop the computer. And so you can pretty much see that when we designed our, the only one we walked through in good detail was this load A. We looked at the timing diagram and the rising and falling edges of the clock. Um, pretty much you could see that we were making every decision based on and making every setup, i.e., setting different lines, you know, saying this component read its value in from the bus, and this other, while this other component is putting its value onto the bus. All that was based around the clock. And so it turns out if a very simple way to actually halt the computer and prevent it. Uh, there's two things you could think of. Um, my mind when I went to this was actually just stopping any instruction from getting in the program counter. So if the program counter, if the program counter could never update, then no instruction, you know, could be executed. But then there's actually like something incorrect about that, and that there's still a value in the program counter. So that value cannot, can be interpreted as an instruction and it can't execute. And so that wouldn't work. Nor would blocking the program counter from writing out onto the bus work because, uh, basically we, we always say that if a component is reading in from the bus, there has to be something on the bus. You get into a weird state if you have a component that tries to read on the bus and there is physically nothing on it. I.e., every other component that could write onto it, namely, the program counter here, is actually disconnected. So you might want to think, let's stop the program counter from being able to write its value onto the bus, and therefore when we try, you know, looked up that address and RAM and treat as instruction, it, it won't work, but the behavior is somewhat undefined here. Um, what's easier, it turns out, and I think the only solution for the sake of our simplistic computer, is just blocking the clock. But we discussed earlier that the clock is always just going up and down, like it's a physical circuit, and that's not something we can necessarily control. So the way we circumvent this is by actually all these components that depend on the clock, they don't quite depend on just the clock. We'll actually end it with some signal. Um, and basically whenever we set that signal, it'll, if it is set, it'll prevent the, uh, the clock from actually making any progress. So it'll force it to either always stay low or always stay high. It doesn't really matter which we let it at. Um, but what we can do here and how we can build that circuit is so our instruction is called HALT. So I'll just call it HALT. But it'll just be quite literally the input to a logic gate. We have this HALT sign and this clock sign. And we also probably want, uh, or let's and them together. Um, what I was going to say is we probably want it such that if our HALT line is zero, everything is allowed to run as normal. But then the, when we set our HALT line to one is when we block the clock. So, uh, what I'll actually do is instead of hooking in the HALT line directly, I'll invert it and then feed it in here. And then this output is the clock that goes to the rest of the computer. And so it turns out that this then is another circuit for us to use. And I'll kind of move this diagram up here, and we can shift it all down a little bit. Cool. So what this has the effect of doing is what normally, in normal execution, this HALT line is zero, which means we, the inverted value is one, and so the output of this AND gate is just whatever the value of the clock is, which is this circuit that's always just pulsing between zero and one, so it's frequently changing, it's volatile. Now, if we were to flip the HALT sign to one, the inverse would be zero. And hopefully, you know by now that anything ANDed with zero is just going to give zero itself, which blocks the clock from making any progress. And so that when we actually get to it and figure out how to implement the HALT instruction, all that instruction has to do is flip this HALT line to true, and it'll stop. It'll actually just break, like anything from making further progress. The computer gets into a quite literally unrecoverable state, and nothing can make progress.

So now we can tie this all together and figure out how our control works. And I can guarantee that you could reason about this yourself based on everything we've learned in the video so far. There is nothing I'm going to introduce here that isn't already known to you, and that's pretty powerful. Um, that being said, I remember when I was learning this, this was insanely bizarre to wrap my head around, and I had to have it spilled out to me. The entire time I was building the computer, I could understand how each component works. And it was like, oh, that's how the ALU works. Oh, that's how a register works. That's how a counter works. That's how RAM works. All makes sense. And then when it gets to tying it together, you're kind of like, okay, well, I understand how each of these components work individually, and I understand how you can punch lines to kind of have them communicate with each other via this bus, but how can the computer do it all itself? And, you know, how do we remove the human element of this from the loop, assuming that we have some, uh, program specified in RAM? Um, so let's tie it together right now. And I'd say this is probably the crux of the past eight hours of this video. Um, it's crazy for it to be the crux because we're not going to build anything you already have not seen, but it is very powerful to see how something you have already seen can be reused again in a totally different manner to bring so much more complexity to the system. So, let's think about so far we've been serving as the control. Let's been thinking about, um, what we've been taking in as input to the control. So us input, um, and basically there's a few things. So number one is the op code from the instruction register. This, you know, this, this line right here, this arrow. Um, whatever the op code is in that instruction register, we use that to denote what instruction we're executing in. So our inputs are, you know, this op code, and that's four bits. And then we also said that we were designing this computer such that, oops, some weird coloring happened here. Um, such that each instruction that we defined in our table took five clock cycles to add. And when we walked through the load A instruction, you know, we went through the little timing diagram and showed, hey, we'd set this here and, you know, clear it here, and then set these next thing here and clear it here. Um, and so we were internally keeping track of our clock cycles. Um, turns out we're going to want to have a counter. And so we can, we want to count, you know, just from, uh, zero to to one, um, or sorry, zero through five, I guess, zero through four here. So what we do is, um, we have to represent five values. So we'll build a simple counter on the side here. And the counter we build is going to be very similar to the program counter up here. Except the difference is is it's always just going to be counting one to five. Zero to four, to be correct here. It's going to count in cycles of five and then reset on its own based on the clock at any given time. So instead of it needing to be explicitly set by anything, we already know that each instruction is going to use five clock cycles. When we get to clock cycle number five and do our work, we should reset to zero because now we're counting for the, the start of the next instruction. So, we kind of have this counter circuit, um, counter, and it has this same plus one, except its input signal is just always going to be the clock. So I'll highlight that too for sake of consistency. So the output for our counter, our counter is actually going to be three bits. The reason is, um, we need to count each instruction takes five steps. We need to count 1, 2, 3, 4, 5. If we do that in binary, you know, it starts with 000, 001, 010, 011, and then 100. These are the, uh, five different values we use to denote whatever step we're currently executing of the current instruction we're on. So not different instructions. Instruction is an entire one of these commands right here. But to implement each of these instructions, we use five steps. And five steps would be five clock cycles here because we're counting up one every clock cycle. And so this is three bits. So, uh, that was a little bit of a side tangent, but that is to say that, uh, this counter goes into our, um, you know, it's part of our control brains. You know, we'll just call it like step number, represents the step number. What step are we on of the current instruction? So each time we're setting lines, it matters how far along we are in our current instruction. So that's also something we've been interpreting as an input to our control. And we haven't explicitly designed this as a counter. But, you know, when we've been doing it, we've been looking at the timing.

sequences, looking at, hey, the clock's low and it's about to go high or vice versa and then setting control lines appropriately. As we shift the uh discretion away from us, mainly punching lines uh into the computer, the computer needs a way of knowing what step number is on. Is it on one, two, three, four, five? And so the easiest way to do that is just to have a register that is a counter and then feed that as input to our control. And our control then can say, rather than us as a human on step five, we could just look at what the output is on that step number line to figure out where we are in terms of execution of the current instruction. So that's the second step, or sorry, second input, step number, and that's three bits. And then the last thing that might, you might think that's all, but recall the uh two jump, the two conditional jump statements. Um, those perform a jump operation based on the last output of the ALU, which is stored in this flags register. So that flags register, we also need to know what's in it for us to make our decisions. Um, so that's also something we've been considering as input when we've been implementing the control ourselves. And so, you know, we have the zero flag, which is one bit, and then the carry flag, which is one bit. And so these are all the inputs we've needed to then look at a timing diagram and figure out what inputs uh or what control things need to be set at any given time.

So what are the outputs now? So any step we've been looking at, hey, this is the instruction in the instruction register. Here's what step number we're on. And for two of our instructions, our conditional jump uh instructions, we're also looking at this flag register. We, for the most part, we aren't really looking at it, but we, you know, we are for two instructions. So it turns out for the bulk of them, we ignore them, but you know, we can't just turn things on and off for what our control looks at when it's the brains. Uh, so we'll have to just have the input be fixed all the time. You know, you couldn't pick up a wire and throw it away. That defeats the purpose because then you'd have a human be intervening. Um, the control itself will just know, like if you're doing a load A instruction or a subtract instruction or something of the sort, and it doesn't matter what's in those flag uh in that in that flag register, it has no effect on the output of uh how you implement that instruction. So then that's what we've been looking at. I'm calling that as our input to make each of the decisions as to what outputs we set. And so outputs are pretty much, uh, if I've drawn this correctly and completely, should just be everything that's yellow here. So, you know, we've been serving as the human, but ideally, the control would look at the state of the machine based on these inputs and then just know what outputs to set. So let's actually go ahead and enumerate over all of our outputs. Um, and then we can, you know, tie it together in a more concrete place. So we just discussed the halt line, that'll stop the clock from executing. So the moment the computer puts that out, it's actually doomed. Uh, the moment it puts that out and, um, means the clock cannot make any further progress, which means the state of the machine just freezes, pretty much.

Then, uh, looking below it, we have the memory address register in. I'll just call that, you know, MAR in. I don't want to write the full thing out. After that, uh, we had RAM in, which reads the value uh on the bus into the whatever address is stored in the memory address register. Then we have RAM out. And to recall what RAM out does is whatever address is stored in the memory address register, it'll always be looked up in RAM and that value will always be on this side of the line. When we toggle RAM out, it'll just let that value flow to the bus. So in short, RAM outputs whatever value is in RAM at the address denoted by the memory address register onto the bus. Then we have, uh, this instruction register, instruction register out, because sometimes we want to jump to a specific address. So we need to get that argument of the address, or anytime we just need to put the argument uh for an instruction that has an argument onto the bus, you know, we write instruction register out. And then we also have instruction register in, because we obviously need to get whatever instruction we're executing from RAM into that register. So IR in. And after that, um, we can jump to the top of our computer. Uh, for the ALU, we have register A in and then register A out. Register A in will just latch whatever is on the bus into register A, and A out will write whatever is in register A to the bus. So we have A in and I'll denote that A out. Then we have the, uh, ALU out. Whatever the output is, whatever the current output of the ALU is, write that onto the bus. AL out. Then we have, uh, this add subtract line. If we're doing it for any instruction that's not an add or a subtract, it doesn't matter what it is because we don't care what's, what the output of the ALU is. We're not going to interpret it. Um, for add and subtract is the only time the value on this line matters. When we're adding, we just leave it as a zero. When we're subtracting, uh, is the only time we'd ever need to set it to a one. So, we can just call that sub, uh, sub, because it's always going to be zero. The only time we need to turn it on is for doing subtraction. So, let's just call it sub, subtraction. Um, then we have, uh, B register in and B register out. It turns out for the instructions we've defined here, and you'll see this as we, I'll go through and we'll implement each of these instructions, B does not ever actually need to write onto the bus. If we were to expand the computer, then it would. So I'll actually, for the sake of keeping this diagram as minimal as possible, erase that. But you can imagine we could add more instructions here. We talked about this like not too long ago. You know, the out instruction, for example, writes whatever is in the register A to the seven segment display. We could have a similar command for out B, just takes whatever's in the register B and writes that to the seven segment display. So, uh, it's not like it's useless, but for the instruction set we've defined here, it's actually not necessary. So I'll just keep it out for, uh, simplicity. But we do have BN. I'll denote that B I, and then we're just talking about the output register. So we should, uh, talk about that. Uh, the output register in, it's called display in here. I'll just call it OI, output register in.

Then, um, I, I should have started up here. We have the program counter. So we, we want program counter in if we're going to read a value, uh, or increment the program counter. Sorry. And then, program counter out for writing that program counter, uh, value onto the bus. So we have counter increment and then counter out. And as I'm writing this, I realize we have a little mistake here where, uh, we know for our jump instructions. What the jump instruction does is it tells the computer, hey, like, if the program counter says the next instruction executes at address five, ignore it and jump to actually this other address. So right now, we actually can't support that because our PC inc will actually only increment the program counter. But we also want, uh, a way to read a value from the bus into the program counter. So you can imagine we could just update our little circuit here because it's just a little ALU, um, and one line is doing the increment. Uh, another line could actually just read a value into the underlying register that's the operand of the ALU. And so we can call that, um, J. We'll call that jump because that's the only time we ever need to to write a direct value into the program counter. So, sorry for the confusion there. We actually weren't fully complete. Jump. And then the very last output we might ever set, uh, is back here. Whenever we do an add or subtract, if we do an ALU operation, we need to update the flags register because if there's an add or subtract and then there's either a jump carry or a jump zero afterwards, that means we would need to have known what the output of the last ALU operation was. And so basically whenever we do an ALU operation, we will terminate it or just along the process look at the output and conditionally set these jump and carry flags, which we talked about how to build those, set those, um, circuits. They're relatively simple. And so, um, these are all of our inputs and all of our outputs, and I've kind of listed them out, and we've talked about these. Uh, so I'll stop explaining them because I think most of these should be clear by now. But the, uh, the crux of all of this is I claimed, uh, several times now, that you already know how to build this control. And the reason is, is because the input, i.e., the combination of whatever instruction you're executing, what step of that instruction you're on, and then maybe the ALU flags will tell you exactly everything you need to know to determine which output lines to set. So basically, we know that output is clearly some function of the input, and we also know that each input combination has a well-defined output combination because we've defined every instruction, and we know that the program counter, uh, we also know that each instruction, our counter over here, is only going to go up to five, up to one, zero, zero, binary. Okay. And then we know that the zero flag and carry flag can either be zeros or ones. And so basically, every time there's an input, the output will be the same. So output is always the same for the same input. So f of input equals output will always be true. Which means we basically have a deterministic input output sequencing here. The output can entirely be computed strictly looking at these input flags. And for a given combination of input flags, the output will never change. It'll always be the same. And so how we can encode this is the same way we built out the seven segment display. The read-only memory that took in, that we built earlier, took in a value on a register denoted by eight bits and figured out which of the output lines for these four dis, for I mean, we built a one segment display or one unit of a seven segment display, figured out which of the seven lines need to be set, and so we had like an eight input, um, followed by, I think that's four, five, six, seven dimension output, um, and we said, hey, you, so depending on what the input is for each of the input values, we know, oh, sorry, this also not, this was whatever we could fit in in two digits, I think it was four bits, sorry, but point taken here that, um, I'll say four or eight, I don't remember off the top of my head, but the point is taken that for this read-only memory, its core service was, if you have a, effectively would like to build a lookup table, so for any, for every combination of inputs, has a clear output, and then for any input combination, the output should always be the same. Those two properties are what we discussed that made a read-only memory appropriate here. And so it turns out our control is none other than a read-only memory. It is a ROM, and it takes in four plus three plus two, that's nine inputs. And then it has however many outputs we have right here. And this is pretty powerful because it means if we set up this control ROM correctly, it means that the computer can be fully autonomous. And for every instruction, it'll start, it'll take the value in the program counter, look it up in RAM, get it in the instruction register itself, and then the control knows what values in the instru, what instruction we're executing on. Uh, it also has this counter that's telling it what step of the instruction we're on. And then it can keep setting the correct outputs to execute the current command. And then since we have a line that increments the program counter when the current instruction is finally done, we can just repeat the same process because now our program counter points to the next address in memory. And this is the crux of of tying the computer together. You have now gone from individual components to actually a full computer that's, uh, fully independent and can execute instructions in comma, uh, sequentially, and has the ability to do complex logic where it's not just instru, uh, not just executing instructions top down, but it has the ability to jump to other addresses in memory, i.e., interrupt its own control flow. And not only can it jump anywhere in memory, it can also do conditional jumping, which means your programs that you can publish into this computer can have some, some amount of logic that requires, uh, a forking control. So if do some operation, if the output of that operation was this, do something else or continue on the current path. Um, so this is pretty cool, but you're probably scratching your head a little bit where, uh, we walk through the load A command. And so we, we looked at a timing diagram, but we, we didn't actually see what the inputs and outputs would look like for this control ROM. And we also have a whole bunch of other instructions we haven't talked at all. So to tie this together, what I'm actually going to do is we're going to go build out this ROM, um, and look at what the output should be for every possible input combination. And you've probably seen enough of me drawing to know that my handwriting is bad. So I'm going to switch to my computer and we're just going to do it on a Google Sheets and keep it simple, um, and neat there. But, um, once we do that, we'll jump back to this one more time, and we can reiterate how this all sums together. But this is pretty powerful. Um, we are now, like, I think just like shy north of eight hours of this video, and if you did some hand-waving or if you somehow understand how you could set up the control entirely by yourself, you know how a computer works. Now, this is actually it. This is the true fundamentals. Obviously, this is a toy computer, but this is a fully functioning independent computer. Uh, and that's pretty powerful, but we're not quite done yet because I haven't explained how this control ROM works. So, what we're going to do next, uh, I said we'll swap to my computer. We'll build out what the inputs and outputs for this ROM should look like, and then, um, we'll come back here, tie it all together, and then we'll talk about how we go from like this to an actual more modern computer. Okay.

So what I've gone ahead and done is constructed a table that shows what our hypothetical RAM would look like. And so let me walk through the structure here. So first, um, our inputs are going to be, uh, this column through this column, and then our outputs are going to be this column, these columns. So remember our input, we had the first op code, which was the leftmost four bits of the, um, instruction register, that tells us which argument we're currently executing or should be executing. Then we have the step number. We had that special counter that was, uh, specifically for the control that we just added in last minute, that counts zero and then up to, uh, it counts up to four in binary, or realistically five, um, sorry, yeah, five different operations, zero through four, and then that's here. Then we also had, uh, the zero flag and the carry flag for our two conditional jump instructions where we need to see that. So these are our inputs. Recall this is still binary. It's a ROM, so all of our inputs are going to be zeros and ones, as will all of our outputs. Then our outputs were all the, uh, control lines that we had highlighted yellow in our original diagram. And, uh, we'll walk through this again real quick. So I can make this a little bigger for now. Um, I've, uh, added like acronyms here just because it'll be easier to say rather than having to specify, you know, memory address register in, you know, MI is probably easier to say once we, once we work through these, because these will get a bit repetitive. But HLT is halt. Remember, this stops the clock. MI stands for latch a value from the bus into the memory address register. That's a four-bit register, recall, cuz all of our instructions and arguments are, or so all of our RAM addresses and arguments, all of our addresses are just four bits. RA stands for RAM in, reads whatever value is on the bus into RAM at whatever value address is denoted in the memory address register. RAM out, it'll say whatever the, uh, memory address register is, that's an address. Look up that value in RAM and write it out onto the bus. Instruction register out IO. Take the value that is in the instruction register and put it onto the bus. II is instruction register in. So take whatever value is on the bus and read it into the instruction register. Eight-bit register. By the way, our arguments, our op codes are four bits and our arguments are four bits. But the register itself is eight bits because an instruction has an op code and may be an argument. So four plus four means we need at least eight bits to represent a maximally utilized instruction. AI stands for read an eight-bit value from the bus into the A register. AO says A out. It says put whatever eight-bit value is in the A register out onto the bus. EO, um, stands for ALU out. I actually am not sure why it is EO. Um, I think, you know, we already have AO used, so, uh, I think they, they could have found a better acronym. This was the way I was taught, so I'll stick with it just because my mind is so wired to say EO that if I tried to change that letter, I'd probably accidentally still say EO, and that would confuse you. Um, SU is subtract. This is the line on the ALU that dictates if the output is either going to be register A plus register B or if it's register A, reg minus register B. Um, BI stands for B in, read whatever eight-bit value is on the bus into the B register. OI stands for output register in. So whatever value is in the output register, or sorry, whatever value is on the bus, read it into the output register. Then CE, this stands for counter enable, which is synonymous to incrementing the program counter. So it'll add one to whatever value is in the program counter, and because of overflow, we talked about this earlier, the program counter is a four-bit register. So the highest value we get to is 1111. And because of what we discussed earlier, when you call program counter enable at that maximal value, it doesn't crash the computer or anything because of overflow, it'll actually reset it to 0000. Which means if somehow you have a, a program that spans your entire memory, when you get to the end of it, then it'll actually effectively restart it by going back to address zero and starting again from the top. Um, which, you know, if you don't have a halt instruction, that is what will happen. You should probably end, for correctness, your programs with a halt instruction. But, you know, I'm not here to tell you what to do, and we haven't made any programs yet. We'll, we'll talk about that a little bit too. CO stands for program counter out. So, this takes whatever, uh, four-bit value in the program counter and, uh, writes it onto the bus. J stands for jump. That takes, uh, whatever, uh, four-bit value, the rightmost four-bit value, uh, four-bit values plural, sorry, uh, reads those in, and that's useful for jump instructions. As I'm actually looking at the diagram I drew, I realized my diagram makes it appear as though it's reading eight bits from the bus. That's a, uh, incorrect statement on my part. I apologize. That should be four bits. And last but not least is FI, which is the flags register that we discussed that looks at continually [snorts] uh, looks at the value of the output of the ALU and and determines if the output is either carried, overflowed, or if that value is equal to zero, and then whenever we do an ALU operation, we need to pulse that to latch the value in. That was a mouthful, and that's very similar to what we discussed. Um, and so basically now what we're going to do is, uh, implement all of our instructions, and we're going to start with load A. So from the table we originally had, we said load A's op code was 00001. And so if I look at the inputs, 001, um, and you might be wondering, well, hey, hey, what's up with, you know, all the outputs up until there? So basically what's interesting here is we just know that those are never going to be hit because assuming the user puts in a correct program, there's no instruction we define that has the op code 000000. So conceptually, that should never end up in the instruction register itself. But, uh, we discussed a property of the ROM, and that it's for every input combination, there must be a deterministic output. And it turns out we can still guarantee that. It just doesn't matter what it is because we know that like the input will never be this because this is a malformed op code. Uh, the output never really matters because it, it conceptually should not be reachable. You know, it'd be user error if the user put in an instruction into RAM, uh, and had the op code 000000. That'd be a bad instruction. But if that happens, it doesn't really matter what happens because we don't support that use case. So pretty much the output for all of these lines does not matter. Um, and what we'll default to is that if a line is not set in this diagram, there's going to be a lot more zeros than ones at times, most things will not be set. So, I'm just going to say if I leave something blank, it means zero for these first, uh, entries. Actually, you could actually totally get by and, uh, press in, uh, ones if you wanted to as well. The only thing you just want to be a little careful of is if you, you don't want to trigger this halt line because we saw earlier that if you did pulse that, then the program would stop. Um, it wouldn't matter because again, we don't support the user putting in this op code, but, you know, if we wanted to be a little bit defensive, this is not the, uh, the worst thing to do here. So, um, I'm not going to like read this out. Uh, we just kind of know that like, hey, these, like, these addresses, like, this is not reachable. Um, so I, you know, I could denote that here, but most, a lot of things you'll see are unreachable. Um, are, you know, there's, we don't define all of our op codes, as we discussed earlier. You know, we have two to the four, I think that's 16 possible op codes represented in four bits, and we just do not have 16 instructions, and that's totally fine. So a good amount of our space here is actually going to be unreachable, um, with a technical asterisk that you could reach it if you just put in an incorrect program or incorrect instruction into RAM. But, um, we start with, uh, this part is reachable. Sorry, that's not true. We start with, uh, op code 00001, which was this load A. And, uh, we'll also assume that our, our flags, we're just going to ignore those for now because we know it doesn't matter for this instruction. So it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that's on on the bus, which is the instruction we actually want to execute, and it's going to latch it into the instruction register, and then also as a byproduct of what we defined, uh, we've incremented the program counter. But, uh, that's a different thing than this. This is, this is a step counter used to, used as a counter just for control. The program counter is actually keeping track of what instruction the computer should execute next. Um, but that has no side effect because we actually don't look at the program counter until we get to the next instruction. It's useless for us for now, for this instruction too, specifically. That's not true for some of the jump instructions, uh, that actually need to modify the program counter, but we will get there. So now that we've loaded the value into load A, we've loaded load A into the instruction register. Sorry. Now, uh, the control unit would get this as its input. This would be the op code. And so it, it finally knows after these first two clock cycles, hey, this is the, the op code line is actually saying, um, what instruction we're going to be executing. And that's pretty cool. Um, it turns out, as we did, kind of hinted at, it's pretty explicit now though, that for the first two steps of every instruction, the op code is actually not going to be matter. It's not going to matter. We know that the op code is because it's looking at the instruction register. We haven't put the right instruction into the instruction register. So the op code is nonsense. So it actually, it can ignore it, and it will for the first, every time, you know, our step number is 0000 or 001. We know that for every instruction, we need to do the lookup of the program counter value in RAM and then get that into the instruction register. But once that happens, we get to step 010, that's binary 2. Um, and now we have the op code here. And so now the control knows we're executing a load A. And so what did load A need to do? It needed to take the argument of the instruction, um, and look that up in RAM and then write that into register A. So we discussed this earlier. So I'm going to go, you know, a little quickly here. But, you know, we need to take our, our instruction, is eight bits. The left four bits are this 00001 that denote the load A. The right four bits are actually the address that we of RAM that we want to lo, whose value we want to load into register A. So what we do is we want to put the instruction register out onto the bus. And then we also want to read that value into the memory address register. And so then this is what happens on our first clock cycle. The clock will go from low to high. Uh, we set these values, um, you know, this is our output. So our steps, our step counter, our little incrementer circuit that connects just to the control will start at zero. And so we know that's the start of an instruction. So our A, our, uh, control should just output these two lines because this is what we need to do to get the value from the program counter into the memory address register so we can look it up in RAM. And then the clock is low this entire time. The clock will then go from zero to one, which will latch in the value to the memory address register. And then because our, our little incrementer is connected to the clock, it'll have the side effect of automatically incrementing it, which means we're we end up at the row below here because our op code's not changing and we're ignoring these flags for now, they're not changing. Um, and so that's pretty neat. And so then we're looking, okay, when this, we know the first step was getting the address from the program counter into the memory address register. Now that we've done that, uh, we want to take the output from RAM because that's the actual instruction we want to execute and then put it into the instruction register. So what I do is RAM out and instruction register in. And, um, we're going to do one other thing here. We're just going to choose. We talked about this earlier. At some step in each instruction, we need to increment our program counter so that we get to the next instruction. We're going to do that right here. Um, we're going to choose the second step. It could have happened at any of the next steps after this before the counter over here resets to zero. I'd rather just get it done early so we don't forget about it. Um, and then so what, what effectively happens is the clock will pulse. It'll go from low to high, and that'll take the value that'

um you know ALU to register A and then also update flags. And so that uh completes our our ad instruction. There's a few things I want to talk about before we move on.

So first is this ad instruction actually used all five clock cycles meaningly. Our load a recall the last one we were able to do in four clock cycles. So that fifth clock cycle went wasted. Here we were actually able to get it done in five clock cycles. Um and it turns out every instruction we created in our uh instruction set earlier um can be executed in five or fewer instructions. This is the lengthiest of them. So we just forced like hey because you know all these instructions are the longest instruction uses five clock cycles. We just designed this such that uh every instruction will take five clock cycles. And you could imagine that's not super efficient. We don't want to waste clock cycles uh especially as we're trying to speed up our computer. So we talked about making the computer run faster by making our clock just move faster. But then there is some limitation there because we have to you know wait for logic gates to settle whenever we change inputs to them. Um so the other natural thing to do is okay maybe like make instructions use fewer clock cycles. There's there's two things to make the computer faster. You make the clock run faster or you make the instructions more efficient in themselves. Um so we could have designed this computer uh to you know as soon as that load a instruction was done to move on to the next instruction. We just for sake of simplicity uh aren't going to do that. Um, it's actually not that trivial. All you need to have the instruction do is just move on to the next instruction address, like reset that uh the the controls uh internal step counter, and you know, that kind of have the effect. But yeah, we're not going to worry about that for now.

The second thing I want to talk about before we move on to the next instruction is the fact that these two instructions uh that we've done, load A and AD, look pretty similar. In particular, uh we can actually see that the first two steps are identical. Um and that's because we have to figure out what instruction we're executing before we can actually make the you know personalized or conditional logic of executing that instruction. Um it turns out this will be true for every instruction. the first two clock cycles will always be the same um to figure out what the instruction actually is before we can go about executing it. And this is called a fetch decode execute cycle. So we kind of see that like the first two clock cycles are used to fetch the instruction and then the decoding would be actually deriving the uh like you know we have the instruction what is it actually trying to do and then executing it would actually just be executing it. We don't really have a decode process here because the way we've set up our control logic it's it's just kind of deterministically responding to the input. So decoding it is effectively just looking it up in the ROM, but you don't really see that on the timing sequence because it happens so quickly. Um, so you kind of see like the fetching is clear and then the executing is clear and then the decoding is kind of inherently implicit given to us for free because we're using a readonly memory. The decoding is actually taking whatever uh instruction or inputs we have to the control logic and looking at the corresponding outputs which is just a uh readon memory read operation. Yeah. So our decoding our fetching involves actually moving data between registers. Our decoding is just a lookup in ROM and then our execution is actually the interesting part where we perform the operations.

And the third interesting thing uh before we move on to the next instruction is um I've also said for our ad instruction this is the first of four copies and that is because uh our zero and carry flags don't change what we do for our ad operation but we do need a handle that those values might be different. So especially after this uh like let's suppose we do this add operation um and then there's a load a afterwards because we set the flags register in this ad operation uh it doesn't affect a load a operation the load a operation doesn't care what's in those flags but it does mean that the input to the ROM can change uh and so that's why we had the we talked about copying this load a four times uh we actually have to do the same thing for add um and we'll see that that also is true for most other instructions.

So yeah, that's uh that's our add instruction. Let's move on to the subtract instruction which is very similar to the add instruction with the difference being that you know instead of register A equals instead of register A equaling register A plus RAM of arg ram at the address specified by the argument. Uh it's the exact opposite. We just subtract. And so you can kind of imagine before we even spill this out that the uh the instructions, the microode that we're putting out for of the ROM are going to be very similar to this ad with the only difference being that we're going to have to just uh set the ad subtract line in our ALOU. So I'm actually just going to copy over everything we've done. And all we have to do is make one very trivial choice change, sorry. Um, which is we want to set the subtract line right here. So basically everything stays the same and we are uh just telling the ALU because the ALU is always looking at the it's always just taking whatever the inputs are which are these values in the register and it's always just doing an add or subtract on them and that's always available on the output line. So when we put the output onto the bus and necessarily read it back into register A, uh, we can pretty much just get the output we want by flipping the add subtract line before we reinterpret the value of the ALOU. So because the ALOU is just always responding to the add or subtract line, we can just flip it. And there's no issue with timing here that the line is not really a register. So, it's safe for us to just uh flip the line and then read that value pretty quickly afterwards because it's always going to be, you know, it's not dependent on a clock cycle to like latch in that line. Like, we don't need to tell the ALU before we do an add or subtract, we're going to do an add or subtract. We can just tell it as it uh does the computation to consider whatever is on that line. Um, and yeah, everything else is exactly the same. Uh, and then similar to what we described before, this is replicated four times in memory or sorry four times in this readon memory.

Okay, let's hop on to the next instruction store a. So um this will take an argument and it'll basically say RAM at the argument should equal whatever is in register A. So basically we need to take whatever values in register A, get it on the bus and throw it into RAM. Um it lets us move data. We've talked about moving data from RAM into the ALOU. We are now going to talk about moving data from the ALOU into RAM. And because everything is connected to this this central bus unit, uh, we have all the control signals uh available to implement that uh instruction with what we have defined here. So uh let's start. First, as usual, we don't know what we're executing. So, we need to look up the instruction uh based on the value that's in the program counter. So, we put the uh the address, we put the value from the program counter out onto the bus and read it into the memory address register. And then we take the uh output of RAM, read that into the instruction register. And then we also increment our program counter so that uh we will move on to the next instruction uh by the time that the our internal control uh step counter goes from four to zero or from five to back to zero. And now that we've uh that's our fetch process again that's the same for all three instructions we've implemented so far. Uh what we now need to do is take the argument of our instruction that's telling us what address we'd like to write the value into and get that into the memory address register. So I'll I'll read into the memory address register and what I'm reading is I'm putting the value uh of the instruction registers argument out onto the bus the right the right uh rightmost four bits sorry. And then this one's pretty simple because now that we've loaded the uh address into the memory address register, what we'll do is we put the a register a value onto the bus, read it into RAM, and that's quite literally all we have to do. And then we have a wasted clock cycle afterwards because we've we've uh we've already finished our instruction. So I'll copy over uh our explanations here. And then what we did here was address of IR to the memory instruction register. And then all we do here is uh register A's value reg a into RAM. And after that uh we finished our we finished implementing what we said the store a instruction would do. That's pretty straightforward.

Let's move on to our next instruction which is this load immediate. So recall uh that load immediate was the first instruction we saw where the argument was not an address in RAM an address in memory sorry uh so not a miss but instead the argument was an intended to be interpreted as an immediate binary value. So uh what the argument what the instruction does is it takes register A and it writes uh into register A whatever the argument to the instruction is. So this one's actually easier for us to implement internally because we get to skip having to go through RAM. Uh we get to skip that indirection and instead just take whatever value the argument is, treat it as a binary number, not as an address, and uh throw that into the A register. So let me go ahead and copy. We already know the first two instructions are the same. I don't want to keep repeating that, so I won't anymore. Um now all we have to do for this one to implement it once we know it once we know we're uh executing a load immediate um all we need to do is take the argument that's stored in the instruction register put it onto the bus and then also just read it into the A register um and then we're done. So then IR to register A is what we're doing here. And then our last two clock cycles are wasted. there no ops and I can denote that for the ones above as well. Um, and this one's interesting because it's so simple to execute. Uh, we actually have two wasted clock cycles. So only three of the allocated five clock cycles here are being used meaningfully and the others are are are useless. So you can imagine that's it's pretty inefficient. You know, we have like a 60% utilization as measured by clock cycles for actually doing work that we need to. Um, and yeah, that's a that's a bad that's a bad one. And the reason we have two instead of one like the previous instructions that had a wasted one is because we get a skip uh skip a RAM lookout a RAM lookup sorry because rather than the argument being a address that we needed to go decode in RAM which would take an extra clock cycle to do we can just we got to circumvent that for free just by being able to use the argument literally without having any indirection through memory. So you can kind of see that uh because of that looking up a value in RAM is slow. So operating with these registers is really fast but then operating with RAM is a is a is meaningfully slower. Uh and so it turns out uh modern computers will have many registers not just two that feed into the ALOU but you know a set of registers for you to use for scratch work and there will be dedicated instructions for reading and writing values into each of those registers. And that makes it easier for the it makes it faster for the computer to implement instructions and do work because it can skip every time you're operating with uh a register value instead of a RAM value. It's faster to access that value so the computer can execute the instruction faster which overall improves the uh performance of whatever program you're running. If you've written code before, then certain programming languages, maybe you've seen it, have a keyword. I'm thinking about C specifically here, uh, called register. And so you can kind of tell the computer like, hey, this value is going to be worked with a lot. Um, so put it in a register. But, uh, I get ahead of myself here.

Let's talk about jump next. So, jump's a little interesting because the argument to jump and I guess recall whatever all jump does is rather than the program counter executing sequentially, it just keeps counting uh, from address one, treat that as an instruction, execute it. then it'll say look at address two treat that as an instruction and execute it. Then look at address three treat that as an instruction and execute it. Uh instead jump lets us tell the pro lets us tell the program counter to like not break it lets us break that sequential ordering and say hey if maybe I'm on instruction five right now don't go to instruction six uh jump to maybe instruction 10 or zero or any of them. So all it's doing to implement that is just setting the PC equal to the argument. The argument is uh an address, but it's not an address we need to go look up. It's an address we just need to change control execution to after this current instruction. So uh our first two clock cycles for the decode part are the exact same. And then uh this one's also pretty straightforward where all we need to do is take the instruction registers argument, the instructions argument which is in the instruction register, put it out onto the bus and then read it in to the program counter which we have this J line for. Um, and that's all. And then our last two clock cycles are wasted. So all this does is say program counter equal uh sorry instruction register to program counter. Um, and there's something interesting here and that this instruction touches the program counter twice because first we actually increment it because that's what we've been doing for every other instruction and then we update the value that's in here. So it turns out because it's a jump instruction and um we know that the program incrementing the program counter is useless because we're changing control flow to go somewhere else immediately afterwards. Uh it it's possibly a little redundant to be incrementing the program counter here, but um we could so we're conceptually we could avoid incrementing the program counter here. Um, but uh the thing is we know we don't know until after this clock cycle because this is the fetch that we're executing a jump. So it's we don't we can't know that we're executing a jump. So we can't decide to skip incrementing the program counter here. So if we had designed our implementations for all these instructions to increment the program counter at the very end of your instructions implementation then we could safely omit it here like we did on the fifth clock cycle. then we could emit it here. Um, because we're choosing to do it at the start, we can't make that mission, but it also doesn't break anything because it's safe to increment the program counter because it happens before we update the value uh that we're jumping to. So, what would be bad is if the user was saying if the user had jumped to address 5 and we wrote address 5 into the program counter and then afterwards we incremented it. That'd be bad because it'd actually end up jumping them to six because that's what the value in the program counter would be when the CPU goes to execute the next instruction. Uh we don't have to worry about that because you can do whatever you want to the value in the program counter if you're going to eventually write in the intended value afterwards. So uh just wanted to have a little bit of discussion there. Um, this instruction as is the case for load immediate and store a also has to be repeated four times and it's identical for each of the combinations of the zero flag and the carry flag.

Up would be jump carry. So recall that jump carry is the same thing as jump. We only perform the uh updating the program counter. I we only do anything if the carry flag is one. So this in in interpretation means if the last ALOU output had a carry out on the most significant bit of the ALOU then we will perform this jump otherwise we will do nothing. So our fetch and decode are the exact same and also copy over this for just completeness. Now, if we know we're going to jump, it's pretty straightforward. All we know we have to do is uh put the instruction register out and read it into the program counter. And that way you know that uh when you get to the next instruction, i.e. when this our internal counter for the step number uh internal counter meaning internal to the control logic resets back to zero it'll go and fetch the PC value which is now the address that we intended to jump to. So uh it just sets us up for executing the next instruction correctly. And for jump carry though, uh we want to know if the carry flag was set from our ALU's flags register. And that is why we need this context to know what control lines to set, which is why we have these uh this carry flag here included as one of the inputs to the control logic ROM. And that's because we as we were doing this as humans, we know that we're making a conditional decision. Hey, based on the value in the carry register, we will make a decision about whether or not to actually jump. When we're automating this and letting the computer make the decisions itself, we need to feed this as input to the read only memory. So for this specific uh instruction, it actually does matter what the zero sorry what the carry flag is. And uh it doesn't matter what the zero flag is, but similar to the way we had to repeat all of our previous instructions four times based on the combination of the zero flag and carry flags. We're also going to have to repeat this for four times because there's four combinations of the zero flag and carry flag. But it turns out that the value of the carry flag uh actually influences what we do here. So it's not going to be a straight copy four times across the ROM to account for all four possible permutations. Um it will appear for all four permutations, but the microode will actually be different based on the value of the the carry flag here. So in this case, the carry flag is zero. So we actually don't do anything. Um, and so we just do nothing for the we waste the the remaining three clock cycles of this instruction. Now if I jumped to uh the spot in the RAM address in the ROM address table where the carry flag was one. If this was a one here then we would do the jump. So we'd have the instruction register write its value into the program counter. But in this case it's not actually. Uh so we'll undo that. I would say let's go hunt for the correct address that would match up to this for the other permutations. But the the sheet I'm making with is non-exhaustive and and it doesn't have that. Um, so instead let's actually uh look to jump zero implement that and then we actually will look at all the permutations.

So jump zero just as a reminder what the instruction does is the same thing as jump carry but our condition to make the jump is if the last alou operation equal zero. Um, and recall we implemented this by looking at the output of the ALOU and oring together the inverse of all of the output bits. So if all of the um output bits are are all zeros, sorry, we and them all together. So we we if all the output bits are zero, then the inverse of all of them would be ones across the board. And then if we and those together, the only way for that output to be one is if all of those inputs are one, which pre-inverter means all of the inputs are zero. Um, so the fetch and decode process is the exact same. But, uh, now we have to look at the zero flag. And the zero flag uh, the interpretation is could be a little misleading here. the zero flag uh if it's zero it means the last alou output was not equal to zero. It's only if it's set to one does it mean that the last ALU output was actually zero. In this case uh the zero flag is zero which means the last ALU operation was not a zero. So we don't actually do the jump. So we also similar to the jump carry we just saw we end up wasting all the remaining clock cycles. Um, but let's go see a more interesting case. So this is how jump zero behaves if the zero flag is zero. Uh, we're kind of interested in the what the output looks like if the zero flag is one. And so I would copy this. Here's another jump zero. So our first two instructions will be the same. Our zero flag is still zero. So we actually do nothing. So we still waste the remaining three clock cycles. Not as interesting. Let's keep going. Here's Oh, here's another jump zero. And we know it's jump zero because the op code is one 0 0. That's how we defined in the table. So I'll copy over the first two clock cycles of the fetch process. Oh, those are gone. Um, so these two are always the same. This time though, the zero flag is one. So we perform the jump. And so what that means is we actually take the argument stored in the instruction register, throw it out onto the bus, and then read it into the program counter, and then we waste the last two clock cycles. So this says PC PC uh instruction register to PC. Uh put the argument instruction register out into the program counter. Um, and there's something interesting because it may not be very apparent but it is also probably worth calling out. Uh this right here is the same micro code for the regular jump instruction that unconditionally makes the jump. So uh every time we are making a jump carry or jump zero and the correct flag is one the microode uh i.e how we uh implement the instruction is called microode uh setting each of these lines output lines. Um the microode the control output is always the same and so it's based on uh the inputs that actually determine which of the uh which of these control lines will be set for the output. Um, so it means we do replicate this this instruction four times like every other instruction is replicated to handle for every permutation of the zero and carry flags. But unlike every other instruction we've seen so far that ignores it, this one actually has to look at those flags to make a uh well-informed decision to know what it should or should not do. So that's pretty interesting because this is kind of how we make decisions in our in our control. um you know everything else everything else in terms of instructions we discussed so far uh it's easy to tell the control what to do strictly based on you know for hey this op code represents this instruction the steps are always the same but then for the the jump carry and jump zero instructions uh they aren't necessarily the same uh and we'd actually need to look at it so as a human we said uh I'm going to look at what's in the flags register to determine if I make this jump uh and we how we bridge that gap of us making a decision conditionally uh was feeding it as input to the readonly memory and generating different outputs based on the different input combinations. And so because a readonly memory has to be we have to fully map out every input and output combination we can pretty much say hey for each of these input combinations this is what you should do. So we are we give the readonly memory a very verbose yet complete and necessary uh set of [snorts] input output combinations to handle for this. Um, so for every other instruction if we wanted to add more conditional instructions to this computer uh you kind of have to find a way to incorporate that logic uh into the readonly memory by adding in an extra input um that represents the decision state for what you're making that instructionally do. And then it'd also have to be replicated however many times. Um, cool. So that's interesting. Uh, let's see if I So the remaining jump zero one 0 0. Um, the jump flag is set. So we also perform the the jump operation. So I can actually literally just copy the implementation for jump because it's the same. Cool. Okay.

So, that's how we implement our conditional logic onto our final two instructions. Uh, I know this has probably gotten a little bit repetitive, but I wanted to be as complete as possible because I part of the video is I do not want to leave out otherwise meaningful information as I explain things from scratch. Uh, so I want to minimize the amount of handwaving I do until we have the barebone CPU working. And then as we talk about how this translates to a more modern CPU, more modern computer, uh, then I'll do a little more handwaving. But um our second to last instruction was out and all it does is put the value in register A into the output displays register. And that has the effect of updating the seven segment display to show whatever's in the A register. Even uh in future instructions change the value of the A register. um it won't update the display explicitly. So the display is not always just hardcoded to the A register. Remember we built a new register uh and the display is hardcoded to that register. Um, so our fetch decode execute cycle starts with fetch. We do the same thing that we've done for every instruction. Oh well that's interesting. Okay. Um, and for this one, it's also pretty trivial. All we need to do is get the value in the A register into the displays register. So, I'm going to put the A register out onto the bus and then I'm going to read it into the uh display register. And uh once we do that, uh I'll mark that as register a into display reg. um our remaining two clock cycles can be wasted here. So that's a pretty simple instruction.

And then this brings us um to the halt instruction which is the last one of them all but worthy of instruction worthy of discussion. Uh, and for both the output and the display instructions obviously these are repeated four times uh based on whatever the inputs uh for the zero flag and carry flag are don't affect what these operations do. But we still need to define them because that is input to the ROM. Um, I display should do the same thing uh if if the zero flag is one and the carry flag is zero as as it should as if both of those flags are zero. But we actually need to go specify that in the ROM um for completeness. So our halt instruction is pretty interesting where all we have to do is set the halt line. And recall that the moment we do this because the halt line is is connected to the clock, the halt line is inverted and then connected to the clock. So the moment we set halt one, the inverted value of halt is zero. And since the clock is anded with this, it means the clock output that we connect to the rest of the computer is just going to get stuck at zero because zero and anything anded with zero is zero. So even if the clock itself is going high to low, high to low, uh when we end it with this inverted halt signal, it'll block that from actually carrying through out of the endgate. Um, and so as soon as we get here, the computer cannot make any progress. So it actually doesn't matter what we specify for the remaining two clock cycles here because not none of it's conceptually possible for it to get executed. The only way to get the computer out of this state would be to physically turn it off, turn it back on, reprogram uh your memory and then things will be good to go again. Um, cool. So that concludes us implementing each of the instructions. What I'd like to do next is uh define a program with the instructions we've created. So I'll switch over to this other tab here. And what I've copied over is all of our instructions and their op codes. We know what they do. So I don't carry over a description. And then uh a conceptual layout of RAM um where here's our 16 different addresses starting from zero uh in decimal. And then this is the binary representation i.e. if we wanted to you know lo access that value either read or writing into it. Uh this is what we need to put in the memory address register. So it's just the the binary equivalence. And what I'd like to do is let's write a simple program that just starts with 15 uh and keeps counting down by one and displaying that on the uh our seven segment display and then once we hit zero we stop. Uh it's a trivial program and you'll probably see why I pick 15 very very shortly. Um, but if we think about what we need to do to get this program in RAM, there's a few things. First, we need to you know for our our primary loop, it's going to be doing subtraction by one each time. Assuming we get the value 15 into the a register and we get the value one uh somewhere else in memory then we can keep calling the subtract instruction with wherever the one resides in memory and then we know every time after we do the subtract instruction we want to write the display to write to the output display and then we check if we're at zero or not. If we're not at zero we could jump back to our same uh subtraction instruction. uh otherwise if we are at zero we need to jump and and have this um halt command. So let's kind of think about the very first thing we need to do. Um, the first thing we'd want to do is get this the value one somewhere in memory so that we can always use that as our thing that we're subtracting from. And if I if we were to count down from two, we would need the value two somewhere in memory. And that's because the subtract instruction uh the operand is not the value you want to subtract from whatever's in the A register. It's the address to something in memory and that value at that address is what you want to subtract from the A register. So uh the first thing I want to do is actually get um a load immediate of a one into the A register. So the reason I'm doing this uh is that in the only way we can write something to RAM is with our store a instruction. So if we want to get the value one somewhere into RAM, we'd actually first need to get that value into the A register and then we can write it from the A register into RAM. And so the load immediate is what does exactly that. It treats the argument as a literal 4bit integer and then it'll put that into the A register. So uh we can comment this you know register a equals 1 and then uh the actual RAM value the actual value we put in RAM to do this is the load immediate argument. So 0 1 01 and then the argument here I'll do a space to separate the the op code the operation code the instruction code and then the argument to that instruction just for our readability purpose. Um, and the argument we want to load into the val into the A register is just one. So now that we've loaded the A register with the value one, we want to store that somewhere in memory. And here's where we get interesting. So like our computer will start at address zero in terms of execution when we power it up. The program counter will always start at zero just by assumption. Um, we kind of you get to use RAM however we want. So it's kind of us up to us to figure out where we want to put the uh the the constant one in memory and we designed the program knowing that okay if we store the constant one in memory at this address then every time we do our subtraction instruction this is the address we need to feed it. What I like to do and what you'll probably see if you poke into this further um since RAM can contain both instructions and data people generally like to separate the two. But it's not actually a strict requirement. It's totally up to you. And I think this is where some amount of like creative expression comes into play. Cuz you'll also see that there's probably a different way to implement the same exact program. You might actually have a different thought of how you can get this countdown program. Um, and I'd encourage you to try it out. And we'll we'll show you how to try it out shortly, but I'm going to go down the route I have. So I've loaded the register uh a with the value one. And I'm going to say that uh address 15 is where we're going to store that into. So, what I'd like to do then is store uh the value in the A register into address um 15. And so, what that does is it says mem 15= 1. And I guess I'll just use RAM at address 15als 1 uh for the comment here. And then the actual binary value that we need to load into RAM at address one to signal that instruction to the computer is the store a command which is 010 and then our argument is 1111. Okay. So basically when we power up the computer if we had if we ran uh ran the the instructions uh this in this value followed by this value the output is that uh the value in RAM at this address would look like this. Um if we let that program run but that's not what we want to do. That's just getting started. So now that we have uh this this value address that we're going to say so like this will just be like a hard-coded one is kind of how we will the the value I mean we don't specify that our program will put that in there. Um there's an alternative where we could have skipped these two steps if we had just punched the value the uh this value one into that RAM value to begin with. But I'm just going to work with just what we can express with instructions for now. Um, so now that we've uh gotten our one, which might still a little bit be might still be a little bit ambiguous as to why we've done these two instructions, but you'll see very shortly. Um, we simply want to start with the value 15 and count down from it. So, basically, uh, what we need to do is load the value 15 into the A register. So, load immediate 1111. Uh, ooh, this is actually, um, Oh, that's fine. That's fine. So it what's interesting here is 1111 in this uh instruction is an argument that actually points to this address in memory because that's how we interpret the argument for the store instruction. But as we discussed earlier the 1111 in this load immediate argument is actually referring to the literal binary value um 15 if you were to translate that from binary back to decimal. So uh the effect of this instruction is that register a will now equal 15. And so the actual RAM value that we need to put in to encode that instruction is load immediate 0 1 01 and then 11 one1. Okay. So now we have 15. Um, we need to think about what the user expected behavior of this program is. And what that is is that they should see the number 15 and then they should see the number 14 and then 13 and it should go all the way down until they see the number three then the number two then the number one and then the number zero and then it stops. Let's not think about the end conditioner yet. But uh let us think that the fact that we have 15 in the A register, let's go ahead and show that to display. So all we'll do is an out for our next instruction. Um, and recall that the argument is useless. So to encode that in binary um we will say uh the operation code for the out instruction is 1 1 0 and then the argument does not matter. There's no argument for this instruction. And as we discussed earlier when we looked at how we implemented the ROM over here since we handle um like yeah it doesn't actually matter what the uh argument is here. This could be anything. We just actually don't even use it um for for our our implementation of the microode. So it doesn't even really matter. Uh I'll just keep it zeros for for clarity. Um, okay. So now we're going to say display 15. Okay. So now we've displayed 15. we got to get to 14. So all we need to do since we have 15 in the A register is subtract one. And recall that by the time we get to this instruction right here, by the time our program counter equals the value four, we were guaranteed to have a hard-coded one at RAM address 15. So all we need to do is subtract one from the A register. So we could just do sub and then recall the argument is the address uh which contains the value you want to subtract. So we're going to do 15 here, which is binary 1111. Um, and so this has the effect of of a equals a minus one. And so the binary value that we need to put into RAM to encode that instruction. Uh, the operation code for sub is 0011. And our argument is address 15. So 1 2 3 4. Cool. Um, so now that we've subtracted one, we are at 14. So let's go ahead and show that to the user. So it's the same thing we've done up here. Um, so we will say uh display a um and then uh the operation code is 11 1 0 0. So now that we've subtracted a value and shown it to the user, we need to make the decision. Do we go subtract another value and repeat this process again and show that value to the user? um or are we at zero and should we end the program? So naively what you might think is uh let's just ignore the termination condition of the program is all we once we have gotten to the state all we'd like to keep doing is subtracting the val subtracting one from whatever's in the A register and then showing that to the user and subtracting one from the A register and then showing that to the user. Um, and so what you might be tempted to do here is just jump uh to this address 4, which is 0 1 0 0. And that would work. But this wouldn't stop correctly. When we got to zero, uh, this would jump right back to this instruction. And then you get a weird result in the ALOU because, you know, you're subtracting uh, one from zero, so you'd get negative one. Um, but we said we wanted to stop the program at zero. So what we'd actually need to do is check uh if we have a zero from our last result, which is the exact purpose of this jump carry instruction. And if we hit if we do, we should if we jump carry to zero, uh, we can jump to an address that will end the program uh by just having the halt instruction at that address. So what I mean by that is let's put a halt instruction just somewhere random in memory. Um, and there's no argument to the instruction and so this is just halt. Uh, and then basically what we can then do here is like if we uh jump if our if the result of the last ALU operation i.e. the subtract at address 4 was a zero to this address 10 which is binary 1 0 1 0. Um, and so if we think about where we start here, uh, we display 15, subtract one. So we just and then we have 14 and then we display 14. This jump carry 14 is not equal to zero. So it just continues uh execution. And so then we know that if we make it to this address 7 that it means we actually are not done with our program. So we should jump back up to here to do the subtraction uh again. So I can just jump to address 0 1 0 0. Um, so basically uh check if done and then otherwise um loop. We're pretty much doing a loop here. You know we loop back to the top where our loop is a pretty straightforward just uh subtract by one. So the last thing I need to do is go ahead and specify what the RAM values for both of these instructions are. So this jump carry is 0 1 1 and then our argument is 1 0 1 0 and then regular jump has the operation code 0 1 1 0 and then our argument is 0100. So um if you believe what I'm saying then let's walk through our program. We start we load the value one into register A and then we store that at address 15 in RAM. Then we load the value 15 into register A. Show that to the user. So the user then sees 15. We subtract one from the register and then display that user. So the user sees 14. We check if the result was zero. 14 is not zero. So we move on to this instruction. This jump just says go back to right here. And so then we have 14 and then we subtract one from it. So we get 13. We show 13 to the user. 13 does not equal to zero. So we continue. And then we jump back up here. And now we have 13. We subtract one to get 12 in the A register. Show 12 to the user. 12 does not equal zero. And so we jump back up here. And the process will continue until we eventually get to uh having one in the A register. Then we subtract one from it to get zero. We show the zero to the user. Then we check if the last result was zero. It was this time. So we jump to this address in memory. And this address in memory just has to halt the program. So nothing continues afterwards. So, I've invented this hypothetical program. Um, but like how can we actually verify that it's correct? Uh, it turns out I've built the simulator for the computer we've designed. So, we can go go ahead and punch this program, this this value into RAM, um, and let it run and see if the behavior is exactly what we expect. So, let me go ahead and tab out and let's do that. Uh, a few years ago when I first built this computer, I guess 6 years ago now, uh, I also built a simulator afterwards. This is publicly available if you want to play around with it. Um, there's instructions on how to set it up and how to use it here. Um, I won't focus too much on that. We'll just show how how do you actually play around with it to show what we the program we just made. Um, so what I've gone through and done is uh let's look at the simulator itself. So at any point you can see the contents of RAM. Uh, this is the addressing and you can just click on any value to change it and it'll show you every time. There's like kind of a a log here of every every time something about the computer changes, it is shown here. So if I just set this value to zero, you can see memory address 15 changed to zero. Uh, or if I punch it to one, memory address 15 changed to one. Um, and so this is RAM. And then you can see for you can see the value that's on the bus.

at any time. You can see this value that's in the A register or the B register. And you can see the output of the ALU at any time. And then you can also see what's in the instruction register, what's in the program counter, what's in the output displays register, what's in the memory address register, and then recall that each instruction on our uh computer takes five clock cycles to execute. So you can see what uh each of the steps are. And then it'll also show you for each of the steps um what control lines like what the output of the control lines uh are. And then also what the value of our carry flag and zero flag are. Um, there's a few other things. We don't need to touch on all of it. Uh and you can also see here's the value of the seven segment display. Um, the fictitious one we constructed with just one of these units, but I explained you could probably reason through how the same logic can be expanded for chaining several seven segment displays together to show uh multi-digit numbers rather than the zero through nine that we were fairly constrained to.

And then what I've done is I've gone ahead and punched in our entire program. There is one thing I caught. Um, I used jump carry here. Uh, but our end condition is we don't want to end when our result carries because it doesn't make sense because we're counting down. We want to end the program when we hit a zero as the last output of our our ALU operation. So this should not be a jump carry. This should be a jump zero. Apologies for the confusion. And then the jump zero uh operation code is 10. So, uh, I fixed that. And then you can see I've kind of, um, incorporated that, uh, in the program here.

There's one other cool thing, uh, that this computer simulator has, and that is, uh, there's this button I built called analyze program. And you can kind of see that the contents of RAM are nonsensical. Um, but if I click this analyze program, it'll actually go through and show you what each of the instructions are, um, or what the decimal value of that address in RAM is. It has to do both because the computer is naive. Uh, it can't know if you're using a certain address to denote an instruction or to hold a hold a value. Um, and it turns out any particular address can actually be both. Um, but that's why I do that. So you can see that our instructions here we have load a a store a 15 a load immediate 15 an out subtract 15 and out a jump zero to address 10 a jump to address 4 two empty instructions a halt and then um at the very end we have nothing down here and our address 15 is zero because we have not run the program yet. The first two instructions would get the value one into RAM. Um, so this is identical to what we uh created over here. So that looks good.

Let's go ahead and toggle the clock and uh we can walk through the very first instruction super closely. So uh the very first thing we have is this load immediate one. Let me jump back to our other sheet and we can see what our our uh instructions our micro code should be for this load immediate. So um the first thing that every instruction should do is get look up the value of the program counter in RAM and get that uh get that value. So we want to put the value of the program counter onto the bus and then read that into the memory address register. If I tab over here, I can see since we're on the first step here, uh, those exact things are set. The program counter is going out onto the bus. The memory address register is reading that in. Our clock is low right now. So, if I pulse the clock from high, from low to high, um, we should see that happen. Uh, it's kind of uninteresting because all the values are zero. The program counter is zero. So, we're kind of putting zero on the bus here. And, um, the memory address register is already zero, so when we read it in, uh, nothing really changes. Um, so, uh, let me go ahead and pulse the clock from low to high. Nothing really happens. But then when I let the clock go back down, um, we are, we should end up on step two. And we should see that the next set of operations is getting that output of RAM onto the bus and reading it into the instruction register, looking up the instruction effectively, and then also incrementing our program counter. So uh let me go ahead and put the clock down and you can see exactly those three lines are set. Uh, we increment our program counter and then we are look taking whatever value we got from RAM which should be this 01 and putting it into the instruction register. And so there's this other thing about this uh simulator where this button right here will let us highlight uh whatever the address in the memory address register is on the RAM. So memory address register has zero. So we can see zero is highlighted uh as we trace through the program. It's interesting. You'll see that uh move a lot. Um and so that now we we have done the second step here. So what I need to do is get the clock to be low again. So I'll post uh back down. And the next thing the very last thing we need to do uh for load immediate is take the argument because now we've decoded the instruction at this point. We know it's load immediate. So we know the argument just needs to go out onto the bus, which is what the instruction out does, and read it into the A register. So um let's go ahead and do that. And you can see that on that rising clock edge, the value gets latched in. So the program counter is now one. And then our instruction register has the uh value and address zero, which is the instruction we're trying to execute. And that looks great. And so if I toggle the clock, uh, we fall back low. And we can see that our next set of operations that we're going to do is exactly that. Move the argument from the instruction register, which is this 00001, uh, into the A register. So when I pulse the clock from low to high, this O1, uh, should go into register A. Uh, and we can see that's on the bus already, too. So more interesting non-zero values to work with. We can make some sense of it now. And cool. So the clock went from low to high. And um you can see that the bus now has the bus still has the same value but register A has that immediate one in. And then uh interestingly enough the ALU is just always adding or subtracting what's in the two registers A and B. So we don't care about the ALU output for this instruction but it is a correct sanity check that like 0 + 1 is one. um we know that and then we know from here that after three clock cycles we've implemented we've done all we need to do for the load immediate instruction. So the last two clock cycles are kind of wasted. Um and there's also some detail here. This uh log will pretty much show you everything that we just said. So like we just had the rising clock edge where we read the a registers value in from the bus. Um, so that that happens as well. And that's just a nice English interpretation of what the computer is doing with each clock edge. So if I toggle the clock to low, um, you can see it's a falling clock edge. Step counter updated the four. Since it's a load immediate, we've done our implementation, so nothing happens. And, um, oops, I accidentally reset our SAP. Uh, I clicked the reset button. So we've we've gone back to to reset the state of our computer. If I just toggle it to get back to where we were. Um, there's there's nothing crazy to it. So, we're at step count five. We hit the rise and clock edge and when I fall when I fall, we're done with our instruction. So, now we go our internal counter used for the control resets its step count to one. And now we know we're on the next instruction. And uh that next instruction, if I analyze our program, was the storing that value into address 15. So, I'm not going to walk through each of the five clock cycles here. What I will do is I'll pulse the clock five times until we get back to step counter one. And what you'd expect to see if everything's correct is that afterwards the value in RAM at this address 1111 should equal um the value in the A register which is just one. So, let's go ahead. I'll pulse the clock five times. And you can see that that's exactly what's happened. The value in the uh address 15 of our RAM is now that one. Um, so that looks good. Then so I'm gonna say this looks good. This looks good. Um, now we need to load the value 15 into register A. Let me pulse the clock five more times to do that. And so now we can see register A has this value 1111. And then that looks good. Then we display it to the user. So let's pulse the clock five times. And we'd expect the value 15 to be visible here. Uh, cool. What I should have done when I built the simulator is add an option uh not to just toggle the clock, but maybe to toggle the clock five times or through five clock cycles so I don't have to, you know, keep punching it. But uh, it's fine. It gets the job done, I guess. Um, so that looks good.

Now we get into the the loop part here where we subtract one display it and then after that we either repeat that that those two instructions or we end the program. So uh basically what we're going to do is we're going to do the sub. So this should end with uh a being one less than 15. So uh 1111 is 15. We'd expect 11 1 0 to represent 14. And then since we're doing 15 minus one, we'd also expect that the value one should probably get loaded into V register uh to do the subtraction. So let me pulse the clock five times. And you can see both these things are true. So we have 11 1 in the A register which is 14. Uh we accomplish that by loading one into the B register and subtracting it. And uh that looks good. And then now we check this display a. So we should expect 14 to just end up on the display register because we've done our subtraction. Uh we've done our subtraction. So we should show this to the user. So let's pulse the clock through this next instruction. And you can see that's the exact case. We have 14. And now uh let's do a little bit of checking. Um now we should expect uh this jump zero to not to be a noop. Uh we should not end up jumping to this address right here. So if I pulse the clock five times uh what the what should happen afterwards is the program counter should equal 0 uh 1111. And that 011 is going to tell us to just jump back up and repeat the loop. So let me pulse the clock five times. And we can see our program counter is 011 as we expect. So we uh did nothing with this jump zero instruction. And then this this 011 0 or sorry this 0111 011. Yes. Sorry. I was like did I say one too many ones? Uh is just a jump back up to uh our our subtract loop. So I'd expect the program counter to go to um address 4 afterwards of this. Let's pulse it and see ourselves. And we can see exactly that our program, our program counter is address 4. And so then we repeat this uh this loop cycle.

So I also built an autoplay because I don't want to trace through this entire program. I built an autoplay that'll just keep pulsing the clock like really fast, low, and high. Uh and you can control the speed here. Um and basically I'm just going to crank the speed all the way up. And we should see that we just count down all the way to zero. One and we get to zero and we end up executing this halt instruction which remember it just blocks the program from doing anything further. So you can kind of see if I scroll to the bottom of the logs here. Um, we set this halt line and then there's a rising edge of the clock, but because the clock is connected to the value of the halt line, it actually blocks the the clock the true clock value from propagating out to the rest of the computer. And so that's how we block execution.

Okay, so this is pretty cool. We wrote a simple program uh and it actually does something. uh it it we chain together these very simple operations and uh use that to build a program that does something. And this is cool because not only like we started from scratch and that we implemented these micro instructions ourselves and each one of those required like very granular uh changes to the state of our system. But then when you cycle change uh bundle a few of those changes into what we called an instruction, the instruction can do something a little bit powerful. Not really that meaningful on its own, but something just a little bit like one action of like move this value from here to here or you know show this value on the display or or maybe jump to this other instruction instead of executing the one that's below me. Um, and so on their own, each of those instructions are kind of trivial, but then when we chain them together, we were actually able to write a program um that actually does something interesting and and has a termination condition. And what's also pretty cool about it is like that program is encoded with literally just zeros and ones. And a few hours ago, this would have been gibberish to you. Uh this this these combinations of zeros and ones would have had no intrinsic value. But it turns out for this specific computer we've designed, this exact ordering of zeros and ones produces a program that does something very interesting to us. We've constructed is trivial, but it paints a very interesting uh portrait of the capabilities of our computer. And what I'd like to do is you can probably imagine the full set of what we can really do with these eight or so instructions is fairly limited, especially because we only have 16 different spots in RAM. So the programs you write are inherently constrained um by the the limitations of how we've constructed our computer. More modern computers have a lot more RAM and a lot more instructions, and we'll talk about that shortly. But, uh, I'd like to try build out something that does something a little more complicated than counting down from 15. Let's see what the most complicated thing we can do with this instruction set that we have is.

So, um, let's go over here to Wikipedia. So, a sequence, just as a quick definition, uh, a sequence is a sequence of integers. Uh, that's kind of a circular definition, but it's literally just a list of numbers. And um, there's one sequence in in particular that's fairly interesting and it's called the Fibonacci sequence. So let's read the definition. In mathematics, the Fibonacci sequence is a sequence in which each element is the sum of the two elements that precede it. So basically we start with the number zero and one and then every element after that is just the sum of the previous two elements. So here we have 0 and one. The sum of that is one. So that's our next number. And then if we have 1 + 1 as the last two elements, the sum of those is two. And then the last two elements becomes one and two. The sum of which is three. And then the last two elements are now two and three. The sum of which becomes five. And you can see that it keeps going. We have 3 + 5 is 8. 8 + 5 is 13. 13 + 8 is 21. 21 + 13 is 34. And uh it keeps going. It grows unbounded. And what I'd like to do is build a program on our computer that can actually count out the Fibonacci sequence for us. And it turns out the instruction set that we have with our computer is totally capable of doing exactly this. Um, and let's also tab out and think about uh something more abstract in mathematics and computer science. Uh, like what is an algorithm? I remember when I was learning computation, kept on hearing talks about algorithms. There's classes you take with the computer science degree. There's one that most people take called data structures and algorithms. Um, and I remember like we we kind of talk about like you know like what are social media algorithms? Like like what's what's the logic behind that? Um, and an algorithm has a surprisingly simple definition. It is a process or set of rules to be followed in calculations or other problems solving operations, especially by a computer. I like the Wikipedia definition a little bit better. So, I'm going to go over here. Um, Wikipedia says, "In mathematics and computer science, an algorithm is a finite sequence of mathematically rigorous instructions typically used to solve a class of specific problems or to perform a computation. Algorithms are used as specifications for performing calculations and data processing. More advanced algorithms can use conditionals to divert the code execution through various routes and deduce valid inferences." So this is an interesting definition. Uh, I think it's a more interesting one for a few reasons. Um, first off we saw that uh we just performed a computation of what we decided earlier. The counting down was just a series of computations. And then uh that was a form of data processing, but like that's not really what the definition is poking at here. But what's also interesting is uh it says advanced algorithms can divert execution through various routes. And um this is kind of the branching we discovered with our our jump zero and our jump carry instructions that allow us to introduce some like decision making into our code.

So what I want to do is write an algorithm for implementing this Fibonacci sequence and then go ahead and actually implement it. Um, I think a good starting point is coming back to this very simple program that we had earlier and and writing an algorithm for it. So uh if we if we wrote an algorithm for this program uh what would it look like about exactly what we did to implement our our instructions here? Um, we have to be very concrete and formal with what we said and uh specify everything very clearly. We have to tell the computer because the computer uh especially the one we built is kind of quote unquote dumb and it'll only tell you it'll only do exactly what you tell it to do. So what we kind of did is we said um we had some variable called the counter. We'll just say like let counter equals 15. And in the algorithm, the algorithm is kind of independent of the hardware of the computer itself. When we went to implement this algorithm in machine code, uh our counter was kind of the A register. That was kind of the register that held the primary state of the program at any given time. And we pretty much said while the counter was greater than or equal to um sorry while the counter is greater than zero what we did is we subtracted one from the counter. So we said counter equals counter minus one and then display counter and basically this this syntax I'm using here is an indentation. So like every time this condition is true, everything that's executed after it or everything that's indented after it will be executed and then it'll check the condition again. It'll come back up here. Um that's similar to the the jumping we have in our code. And then once we get out of this while loop, so well after the only way we can get out of this while loop is if the counter is not greater than zero. And since we're counting down by one, that means it necessarily is equal to zero. And so that means once we get past here, we just end and we're done. So this is a very formal specification um of our counter program.

Let's try doing for the Fibonacci sequence. So let me clear it out here. So in general we said the Fibonacci sequence like for any number it is the sum of the previous two numbers. So like if we let uh let's define like f of i to be the i uh number in the Fibonacci sequence. So we can pretty much say that uh let's say it's zero. We've been learning everything starting with zero. So f of zero is zero. The first number in the sequence is zero and the second number in the sequence is one. And then for every other number, we pretty much say that f of n is equal to the sum the nth fibonacci number is equal to the sum of the number behind it and the number that's two behind it. And so this is kind of what we call a recursive definition where the value of the Fibonacci sequence, the value of f of n depends on recursive calls to f of n. Um, so that makes sense for like us to rebound English, you know, this is just saying start with the numbers 0 and one and then after that for any other arbitrary position in the Fibonacci sequence, go figure out what the two Fibonacci numbers before are and then add those together and that tells you what the current Fibonacci number is. Assuming Ed is the nth number in the sequence that you're interested about. Um, our computer we've built here obviously can't deduce that. Uh, we kind of have to spill that out in a slightly different way. So what we're going to do um is let's go figure out how we can actually build this. So we know that we have these instructions to work with and we also have uh spots in data memory. So I'm going to go ahead and clear out our old program here. And basically I'm going to define I'm going to reserve two spots in memory. Let's just do the last two spots in RAM to represent um like the f of n minus one and the f of n minus2 here. So like the last two values in RAM will always represent uh the last two numbers in the Fibonacci sequence. And then if we can get those correctly, uh if we can always guarantee that to be true, then this means to find the next Fibonacci sequence. Well, to start, we need to load the values like zero and one into RAM here. And you can imagine that's pretty straightforward to do. But then afterwards to get the next Fibonacci number, all we need to do is add the values at these two addresses together. That gives you the next Fibonacci number. You can display that. And then once you have the next Fibonacci number, the n minus one's number becomes the n minus2 number. So you can replace this number right here with what's there because we no longer care about this one for the next Fibonacci sequence uh number. So we'd like pretty much say that this becomes a one and then this value here becomes what the result of the alou was which also happens to be one because that is what 0 plus one is. And so let's do one more practice of that. Um to get if this is our n minus2 and n minus one numbers then the current the f of n i i.e. the next Fibonacci sequence number would be 1 + one. So we could add these two values together. Um, we get the value two. We can store that somewhere else in RAM temporarily. And then this number would need to we want to throw this away and shift this one up. And then now write our two into this spot right here. And so now we have one two as our last two numbers in the Fibonacci sequence. And we obviously want to display that to the user in there as well. Um, and so now if we do that one more time just for sake of tying it together because we worked with zeros and one so maybe the shifting is not clear. But we would to get uh if we have these as our last two numbers in the Fibonacci sequence for wherever our program's at, we add these two values in RAM together using the add instruction. Um, and then we'd get three as the result. We can store that somewhere arbitrary in memory. And then we need to wipe this one away and shift this two up and then bring this three down because that's now our last Fibonacci number. Um, so if we kind of think about how we want to specify this as an as an algorithm, um, let's just call this value like a and this value b. And a and b are always the last two numbers in the Fibonacci sequence. So what we'd want to do is pretty much start by getting the values zero and one into these spots and rams. Um, because this is uh the the first two numbers in the Fibonacci sequence, we kind of know that RAM is all zeroed out. So the value here will already be zero because of like how our program instantiates. Like we're just going to say that RAM is all zeros. But we need to get a one into here. So that's pretty straightforward. Um, like pretty much we can say a is already zero. Then we can say B becomes one. And then what we'd like to do is uh add at any step the two values together. So we make a new value called C and C is equal to A plus B. And then we can display C to the user because that's the next Fibonacci number. And then we need to say that uh A becomes B and B becomes C. And that's how we kind of shift up one here. And um after that we can pretty much jump back to uh jump back to uh the C= A plus B instruction. Um, and so what we do here is we we get our first two Fibonacci values and then we begin a cycle of calculating uh the next Fibonacci number. So our every time we loop through and jump back up to this, we're trying to find the next Fibonacci sequence, assuming A and B are the last two Fibonacci numbers we worked with. So by definition of the Fibonacci sequence, we can trivially compute the next value just by adding A and B together. And then that's the next Fibonacci number. We display that to the user. And then now that we have three Fibonacci numbers, we throw away the oldest. The oldest is A. And so then B becomes the older one. Now, so uh what was previously in the B becomes assigned to A and then what was in B is now our newest Fibonacci number which is the one we just calculated up here. So we can set that equal to the value of C. Um, and so this is pretty straightforward. Uh, let's actually go ahead and this is like kind of our formal algorithm. Um, so I guess like if we wouldn't make this fully algorithm uh we could say like uh wall like one is equal to one. So just this is wall one is always equal to one. So this will always be true and this is kind of what the uh the the code would look like. So this would keep counting Fibonacci sequence numbers forever. We start with uh like you can say like let a start with zero, let b start with one and then wall one equals one is just kind of a little hack around like the algorithm specification to say like do this over and over. And what we do over and over is add our previous two Fibonacci numbers together. Show that to the user and then update what our last two Fibonacci numbers are. So throw away that now that we have three numbers A, B, and C. uh shift it so that what was previous like uh what's currently B and C becomes into A and B. So we set A to B and then B to C.

So let's think about how we can implement this using our instruction set that we have available to us on this computer. So we already know by assumption just that the value in uh in a uh is zero. So what we need to do is get the value one into here. So I'm going to load an immediate one um into the A register. So this just says let me not bold here. Register a equals 1. And then uh afterwards we can go ahead and get straight into the um branching logic. So what that would look like is we need to uh sorry we actually need to take the value we have and store it into register uh store it into this address value. So we take the one that we have and store that into address 15. So this would just say like b equals 1. And then now what we can do is go ahead and start the sequence of adding these two numbers together. So to add two values in RAM, we need to load one of the values into the A register and then load one of the other and then do an add operation with uh the second value. So what we can do is load a with 14 and then so it just says like register a equals a. Uh there's a differentiation here. Uh register A, you already know what register A is. The A down here is just a variable that we are calling. Uh variable meaning uh we will say whatever is in this uh we're going to call a and that value can change it can vary so it's called a variable um apologies I probably use that several times without necessarily clarifying what a variable is but uh forgive me for that and then now we can add whatever is in 15 so then it pretty much says that register A is equal to A plus B so that's exactly what we want and And that that's a plus b is the c value we've described here. So let's denote let's let c equal this equal um address 13 in RAM. So let's go ahead and just uh we want to take that value uh the output here and store it in C. But before we do that we want to show this to the user. So we can do an out here and then we can store the value C into the correct memory address that we want which is 1101. And um the ordering between these two operations actually does not matter. It's kind of up to us that's how we want it. Uh so you know you could have done you could have stored it and then written the out. Uh and the reason we can do that is because uh store a and out neither of those change what's in the A register. They just do some action based on what's in the A register. So this add instruction over here actually mutates the value in the A register. The following two have no effect to the A register. They're independent operations we'd like to do based on whatever was the outcome of this ad result here. So the ordering is trivial. It's it's not perceivable to the human and does not affect the runtime correctness of our program. Um assuming everything else is right here. Um, so now we have our like last three uh Fibonacci numbers like A is the oldest, B is the second like in the middle and then C is the newest. Um, and so what we need to do then is kind of throw away this A, move the value in B into A and then move the value from C into B. So let's start by uh taking the value here and then getting it into here. So all we can need to do to get the value from B into A is do a load A uh of 15. So get the value that's in B into the A register and then a store A where we store it into this address. Uh so that's how we move the value that's how we effectively move the value which overwrites the A with B. Um, so what we do to do that is a load A5. So we say like register a equals b and then uh we can store a into 14 and that just says a equals what was like a is now what b uh is and then the last thing we need to do is get the value from c into the into the b address bot. So I can load into register a this address 13. So it says register A equals C. And then I can use the same trick that we did to overwrite A uh to overwrite B. So I can store that into 15. Um, and then the last thing we need to do to continue this loop is to we've so this is calculated given Fibonacci numbers A and B. Um, everything we've done here uh calculates the next Fibonacci number. So now that we've calculated one Fibonacci number, let's just jump back up here and jump to instruction two and execute the next uh the same set of operations to figure out the next Fibonacci number. So I can just jump to two uh one zero and then this says continue. Um, so if I kind of map that out, these are our instructions. Um, we can kind of see that we let a we get this first one for free. This a is equal to zero. We get that for free just because we already know that RAM defaults to zero values. So then the next one that we have to do ourselves is getting the value letting B equal one. And that's exactly what we're doing um in these two instructions right here. We're getting the value one into register A and then writing that into B. That's how we do this. We have to do two instructions because of how restrictive our instructions that we have defined are. But they exist like there's enough instructions to do what we want to do. And then you can kind of see that uh this is our loop part. But so C equals A plus B is implemented right here because we load A into one of the ALU operands and then B into the other ALOU operands and we add those together and we get the value C and then we store that uh into the value C. Sorry. So this is these three instructions implement C equals A plus B. Then the display C is trivially implemented with the out instruction. And then these four instructions implement the shifting um of replacing um A and B uh with B and C. And this um program if we let it run will count Fibonacci numbers for us.

So, what I've already gone ahead and done is kind of loaded some of these values into RAM. Let me go ahead and clear uh this because that's not correct. And if I reset everything here, let's go ahead and run the analyze program and see what we have. And so, uh, if I'm matching up what is over here with over here, I see a load immediate one, a store a 15, a load a 14, an ad with 15, a store with 13, a display, a load a with 15, a store a with 14, a load a of 13, and a store a with 15, and then a jump back up to two. So, this is the correct program. I didn't specify the RAM values here, uh, but they are punched in here. Um, so let's go ahead and just let it rip. Uh, I'll autoplay this, but uh, the Fibonacci sequence, we can I'll type out some of the numbers so we know what to expect. Um, we know that we start with zero and one. So, we'd expect to see like one and then, uh, like a a two and then three, five, five, 8, 13, 21, 34, 55. 89. Uh, and so on and so on. Um, so let's just let it rip and see what happens. Uh, one, that looks good. Two, that looks good. Three looks good. Five looks good. Eight looks good. 13 looks good. 21. 34 looks good. 55 looks good. 89 looks good. And um, what we're kind of doing is is verifying the program's correctness just by letting it run and see. Uh, that's not the most sophisticated method. Uh, but you know, for the sake of not boring and I can already verify that it does look correct. Uh, that's fine. Um, so what's interesting here is I don't have any end condition. I intentionally did not add a halt here uh just for fun because I want to see like kind of what happens with our computer. So we know that we operate on 8bit values and the biggest value uh we can represent in 8 bits um is the value 1111 1111 and that's equal to 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128. So 255 if every bit position is enabled that gives us the binary string of all ones and that is the maximum value we can represent here and that's 255. So what's interesting is our program will work up to 233. If I continue it uh there should be no issue but then the next value after 233 is 144 + 233 which gets you 377. But we actually can't represent that in eight bits. Um, and so it turns out what happens is there's like overflow. But the computer we saw when we built the ALOU, uh, if you have an ALOU operation that can't be stored in eight bits, it'll only capture the rightmost eight bits there. So, um, what this means is that our program will not break. The computer will not somehow explode or anything crazy like that, but we won't see 233. Uh, we will go from 144 to 233 to something that is less than 377. Um, and it's unclear just based on whatever the binary string is, the rightmost 8 bits of 377. Um, what that is. So if I let this rip a little bit longer, uh, let's go ahead and see exactly that. 89 144 233 and this is where we should fail. 121 is what we just happen to oops happen to get back to. Um, and the the computer won't break. It's just a matter of fact that we say like for our ALU the way it is designed is such that it assumes that the result is always storeable in uh an 8bit value but that's not guaranteeable. Um, and we have the carry flag for detecting this entirely. So when we did go from um 233 to 377, if I had paused the program, we would have seen that the carry flag was set. So what we could have done is recognize that hey, this is the largest Fibonacci value our computer can handle. And so we could have done uh similar to how we used the jump zero to end the program in the previous uh program uh in the counting sequence. What we could have done is used a jump carry to end the program here when we know we get to the biggest value that is represented uh representable. I just chose not to do that because RAM was running out of space. Um, but you know, you can imagine if this was something more defensible, uh, you would probably want to do that. Um, but I think this is probably one of the more complicated programs our simple computer can make. Um, but I'd also like to remark on the fact that uh this is pretty powerful. Like we saw a combination of zeros and ones for a counting program. And it turns out when you interpret those as instructions for this computer, they do something interesting. And now we're seeing something pretty interesting here where this combination of zeros and ones does something totally unrelated that's also, you know, a little more powerful and very interesting. So this is really cool. Um, like something that was just a few hours ago nonsense to you is now something that you can you know you can look at each of these positions in RAM and figure out what the what the interpretation is and if RAM was loaded to that value on some hypothetical computer uh that's what the computer would execute. Um, so that technically concludes the explanation of how we built this computer and everything should be clear from a like ground up like and we'll recap everything we've done eventually, but um, it it wouldn't be right for me just to end here. Like I think there's a lot of questioning around like we've invented this computer but like why do we design the instructions the way they are and like why do we architect it the way we architected it and like how did I know to build this computer? These are all interesting questions and I actually built this computer physically. So, uh, the simulator I have here is cool and all, but I was very interested when I learned this in school. And I found the series online of someone who has a full instructional set, which I'll link because it's an awesome series that I highly recommend watching. And in this series, uh, Ben Eer, his name is, uh, builds this computer, this conceptual computer, from scratch. So, uh, I actually built one and I can show it here. This is what mine looks like in person. Um, it's a bit messy and there's a lot going on. So, let's let me give a few, uh, few bits few minutes of context to explain what's happening here. So, if you look just on the display, uh, you can see this program is just doing counting down. Um, my video, I guess I just happen to start it at the number 71. And then by the time it loops around, uh, looks like it's down to like something like what was that? 59. Um, but there's a lot of components here. So, let's break it down. The first is this clock up here. Um, and I guess as you as I walk through this, you'll see that the way this is physically built, i.e. the layout of all the components is virtually identical to what I drew on my iPad uh throughout the video. And we'll see that like that also came from somewhere. Um, I guess the ordering of the components physically doesn't matter, but I I kept the continuity there to help uh make the understanding easier. So, this is the clock module. Uh, you can kind of see this is the value of the clock and it's just constantly pulsing. This thing up here is a little dial and if I were to twist it, I could increase or decrease the uh speed of the clock. And then this clock is just always pulsing up and down. um, kind of like the uh, you know, the autoplay mode I had in our simulator, but you don't always want to auto play. Sometimes you want to step through specific high low clock cycles. So there's a switch over here and if you switch that it turns off the automatic clock and lets you just pulse the clock using this button right here. Um, so every time you push the button it'll go from low to high and vice versa. So that's pretty cool. That's the clock. Here's our program counter right here. You can kind of see it's counting up. uh, if you repeat those binary numbers and then it jumps uh back down. So it's probably like the subtracting loop is a loop. We saw that in our subtracting program. And then these are the flags registers. So uh the wiring gets tricky to trace here, but uh you can kind of see that there's this these wires here. This is a register chip and that's the it seems to be the output of the register chip and the input on top comes from this wire right here. Um, and this is the ALU. So let's talk about that next. This is the mass of ALOU. We have uh the A register right here. And these lights show the value of the A register. And then we have the um B register should be right here. And then this light right here. I can't quite recall if it's showing whatever's on the B register or the output of the ALU. And then you can kind of see that this thing in the middle is the bus. So the same way, here's our connection of the ALU to the bus, the B register to the bus. Here's the ALU to the bus. Here's the A register to the bus. And here's the program counter to the bus. And then these lights up here show you the value in binary that's on the bus at any given time. Below the ALOU, we have our output display. So we have four seven segment displays chained together. This is the readonly memory and this is the register. Um, so the value in the register feeds into this read only memory which decodes which lines it should set on each of the displays to show the value that we want. Um, and similarly that also connects uh into the bus. So then let's jump over here. This is our memory address register the 4bit memory address register and that reads in from the bus. And um this is our entire RAM unit right here. And then this

would be the uh output of the RAM unit. And then there's something interesting where in our simulator we were kind of just literally clicking values to punch in updates to the memory. Uh in real world, we actually have these these manual switches up here. And I can swap. Uh so if I if I if this light is green, it means the computer's in execution mode. If I flip the switch, uh, it'll actually instead of looking at the value in the memory address register, um, or the value on the bus, I can use these these blue switches over here to punch in a specific address and then punch in a specific value. And then if I pulse this button over here, it'll latch that value into a specific address in RAM. Um, these are really small and honestly a very big pain to use. Um, but that is how I loaded the program into memory. I kind of have to flip the switch so it's on human program mode and then pulse through cycle through every address that was used uh for my program, load the value and then punch it in and then swap the address and rinse and repeat. And then once that's I could flip the switch back uh and then also flip the clock to automatic mode and just let it rip.

Um, this will show you the output. Uh so for whatever address is on the memory address register, the ALU is always looking it up. So this is just always showing the output. You can kind of see like every time the value changes on the input side, the value on the output side changes as well. Unsurprisingly, um here is our instruction register. So the instruction register is eight bits, but the left four bits are the argument and the right four bits, sorry, the left four bits are the operation code, i.e. which instruction we're executing at any moment in time. And the right four bits are the uh argument to that instruction. So I used separate color lights to denote the two. Um, but you can see it's just backed by register and that also connects to the bus. And then here is the meat uh of our computer, the brains that tie it all together. And that's the control logic. So this is the control logic. These are readon memory chips that I literally have to take apart out of the computer and program and then punch them back in here. If we look at what the inputs are here, um you can see that um we have the uh four bits of the instruction register. So the operation code and then we also have this five-step uh counter that represents which step of the current instruction we're on. The way it's implemented in person is a little bit different than the way I explained it. Uh, but the concept is roughly the same or it's it's it's fundamentally the same. So it doesn't matter. I didn't want to introduce this technically uses a different type of counter. And the way it's visualized is whatever step you're on, uh, that light will be off. The clock's going so fast that you can't really tell. It just kind of looks like they're flicker. But if I were to tune down the clock speed, you'd watch a left to right pattern and then it' reset uh in terms of which one is the quote unquote off. And then the uh the value from the flags register is also hooked in here. Um, and then we can see that these yellow wires are just going everywhere because that's the the control output like when we say like RAM out or memory address in or program counter increment like that has to go to each of the components. So you can see like some of these yellow wires going to the program counter, some going to the memory address register control, uh some to the ALU operands, uh some to the output display, and then for debugging purposes, I also duplicated it so I could actually see at any step what lines were being set by the control logic. So that's right here. Um, can't really tell, but there's a label. So like this leftmost light is on if maybe like the program counter increment line is on. Um, in the simulator we built that roughly controls to being able to visualize this right here.

So this is the computer. Um, I built it over the pandemic. And the reason I even came across this is I I learned about it in school for a class I took for my computer science degree. And uh the class uh we didn't build this computer as part of the class. But we did learn how this computer architecture worked uh as a significant portion of the class. But the professor of that class is also not the one who invented this computer. Um, this computer has a name. I've probably let it slip a few times and maybe you could have seen it already over here in the naming. This computer is called SAP 1 SAP1. Um, let's go ahead and Google it. Go straight to Wikipedia because we've been using that. And this says, "The simplest possible computer is a simplified computer architecture designed for educational purposes and described in the book digital computer electronics by Albert Paul Molino. Um, the SAP architecture serves an as uh for building and analyzing complex logical systems with digital electronics. So this is an old book. Um, and then, uh, interestingly enough, this Wikipedia also talks about, uh, Ben Eer, the individual whose video I watched to learn how to build my computer here. Um, but let's actually, uh, go ahead. If you, Turns out, if you Google the book name, um, it's old enough that it's just online, uh, on the, uh, archive. Um, and I mean, you can see this is kind of an old book here. Uh, it seems as though this came from 1993 or at least this version of the book. Um, so this is old here but uh what's really cool is this book kind of does a lot of what we did in the video from scratch which is taking no understanding of how computation works and building a fully functioning computer that demystifies a lot of the blackbox of like what is happening on your phone or on your computer under the screen or like in the internals. So if I skim through the chapters here before he even gets to talking about the computer architecture um you see it it starts with number systems and that's where this video started. We started with you know binary how do we convert from binary to decimal um and you can kind of see that a lot of that is here like decimal to binary and vice versa. And then after that we talked about logic gates you know we we know about the inverter gate the orgate andgate um the some of these other logic gates we also covered like we know about NAND or the exclusive orgate because we needed them to all build this computer. Then uh we talked about some of these without naming them. Um, but like multiplexers we came across for our computer and same for here uh like some of our implementation our intuition for implementing the ROM was using actually some of products I just didn't formally say it cuz I didn't want to bog down with terms um and once we had an understanding of logic gates we went ahead and built the ALU uh and that was able to support bi binary addition subtraction and we learned about we started with half adders and then chained those together um or we got half adders and we chain those with full adders to build our ALU. Um, and then once we had the ALU working, we moved into sequential logic. Everything we had been looking up until that point was deterministic. Uh, sequential logic was flip-flops and latches and how we actually hold data. And you can kind of see that's like a fundamental necessity to implement our computer because that's just like the crux of RAM and register is the need to be able to persist data. Um, that was possibly the output of some other deterministic circuit. After that uh you know these are some of the other registers. We didn't really go into too much there but then we talked about memories. We talked about uh RAM for sure. We talked about readonly memories and then we also talked about the history of some of the readonly memory types. We talked about programmable readonly memories and electronically programmable readonly memories and then EROMs and that was like the foundation of all and then SAP one is the computer we actually built and that's where our context cuts off. The book keeps going and there's a lot more here. Um, I've never read this book but it's probably pretty great. Um, it's very impressive. But the reason it's called SAP one instead of just SAP, SAP standing for simplest possible, uh, is that the author finishes the computer we constructed and then builds two more variants that are just more complicated and get you closer to more modern computers. And we'll talk about some of those changes at a high level. Um, but if we actually jump to the chapter uh starting on page 140 for SAP one um here is what we see uh and you know skimming this I didn't read this too closely either but uh the architecture is is pretty identical like we have the program counter we have memory address register we have a RAM um and you can see the diagram is even identical to the one we designed when constructing our computer like you have two operants to the ALU we had a program counter we had a memory address register hooking into RAM and then we had an instruction register down here um with the readonly memory to decode uh whatever the input is to it and then an output register with a display. Um, and one thing that I do find interesting is if we hop down to the instruction set of the computer uh the author here only implemented few instructions. So there's quite literally only a load a an add subtract an out and then a halt. We have implemented uh far more instructions than what is presented here and some of them are very interesting. Specifically, the jump instructions and the conditional jumping instructions are what allowed us to build out uh both the the counting down program and the Fibonacci sequence. But what's cool is that we were able to implement those instructions without making any real changes to the hardware. Like we didn't add new components that aren't in this architecture specified up here. you know, we were just able to manipulate with incremental changes to what we had already built uh to get the computer uh the instructions that we wanted. So, this is super interesting. Um, I don't think it's probably worth reading the entire book here, especially since we've covered most of what in my opinion is the fundamentals. Um, but I felt like credit was due because I did not invent this computer and uh it's very impressive that this computer exists and I'd say it's very effective um for its goal of building like educational purposes and explaining how computers work from scratch.

The computer we designed is great for educational purposes that we as we just talked about, but it's still pretty abstract and there's a pretty big gap if I ended the video right here of like how does this actually scale to a modern computer. So, what I want to use the rest of the video for is showing like what a lot of this looks like in actuality and how we take this hypothetical hypothetical computer we invented and scale it up to something more modern. Um, I want to start by taking a look at the very first iPhone. Uh, I remember when the original iPhone came out and the first time I played around with it, I was amazed. And I think iPhones are interesting to look at because they have a lot of computing constraints, uh, but are still pack an impressive amount of technology into something that fits in the size of your hand. Um, you know, they're striking things like battery life and then limited storage but then also pack a lot of rich features like very high quality displays and they appear to be very responsive and you can do several things at the same time. You can take a call while you're browsing the internet and uh for that I think iPhones are pretty interesting. So, I'm going to hop over to the uh the Wikipedia for the first generation iPhone, and I'm going to make a claim that this iPhone and every computer iPhone out there has a processor that is not too fundamentally different from what we've designed. You can imagine that these phones are obviously capable of a lot more. Uh, the only output our toy computer has is a simple seven segment display versus you know iPhones have an entire screen they can draw to. So I want to compare the instruction set of the computer we built with that of the iPhone um and see like what about that instruction set is different that lets like lets us scale up from a toy computer to something that's that's actually tangible. Um, so looking at this Wikipedia page there's a few things that stand out. The first is um this iPhone has the original iPhone has 128 megabytes of RAM. So what is a megabyte? Let's start off with a bite. We know what a bite is. A bite is just eight bits. And um our our RAM that we designed had two to the four uh different slots. We had four bit addressing. So we had 16 bytes of RAM in our computer. Now a kilobyte is a thousand bytes. the hence the kilo prefix. A megabyte is then a thousand kilobytes which equals a million bytes. So we have roughly I'm saying roughly here 128 million bytes of address base in our RAM compared to the 16 that our toy computer had. So two things come to mind. Um in one dimension this is a lot of memory. You know, we saw that the programs we built used almost the entirety of the memory of the SAP computer, but that's not going to be as much of a concern if we have 128 million uh slots of RAM. The second thing uh is that the same amount of RAM, we could argue that it's a lot relative to the computer we've constructed, but it's also trivial when you compare it to to more modern phones. Um, or the fact that if I take a picture on my iPhone and I took one right before this just for sake of illustration the size of that picture is 2.5 megabytes which is a lot you know this on one hand we want to say this is a lot of memory but given how much memory is scaled up in modern phones this is no longer a lot and your phone has uh several gigabytes of RAM which is an order higher uh on on the dimension scale a gigabyte would be uh thousand megabytes.

Scrolling down though, that's just one thing I wanted to call out. Scrolling down, there's a lot of um, a lot more technology packed into this phone. So, for example, we obviously know there's a touchscreen, but then there's also a microphone, which you need to make calls. Then there's Wi-Fi and Bluetooth. Wi-Fi for accessing the internet, Bluetooth for connecting to other devices like headsets. Um, and our computer that we designed doesn't have any of these. So, if I'm making the claim that the processor of the iPhone is not too fundamentally different than the processor we described, uh, one of the questions I would eventually like to answer is how do we bridge the gap and get these things like how do we get internet connectivity? How can we even draw to a screen? How do we know when a user touches on the screen? Um, and these are questions that I want to get to in the remainder of this video. But let's keep poking a little further and let's actually look at the processor that's on this phone. Um, so the second sentence here says it features a Samsung S5L8900 SOC. Um, and SOC just stands for system on chip and it generally means that you have a lot of functionality baked into one chip rather than having uh several isolated components. So one chip could have the CPU, i.e. everything we've built thus far in the video and maybe uh the networking chip, the chip needed to like make internet requests versus more traditional computers would have these things be totally separate and they just be connected via wires. Um, so let's read into the the system on chip that this early iPhone used. And um, we can a few things stand out here. Um, obviously these Wikipedias are very informationrich. The first thing I wanted to call out is that let's read from here. The default clock rate of the CPU is normally 666 MHz but has been lowered by Apple to about 12 412 MHz. So what is a megahertz? Let's start with what a hertz is. A hertz is just a unit of measurement for frequency. And roughly speaking or actually precisely speaking uh a hertz just means a cycle per second. So in the computer we built you know the the clock we can crank it up or down to make the computer run faster. And I think roughly in its uh in the maximal video I showed demonstration it was probably running at like two or three hertz. Uh, I think we we're just going through a few few clock cycles every second. Um, a megahertz actually is equ one megahertz is equivalent to a million hertz. So, what this is saying is that um the chip itself that's used in the original iPhone can can hit roughly 666 million clock cycles per second. Um, and Apple has toned that down to about 412 uh million clock cycles per second. A logical question might be why would they ever lower this? You would assume that by making the clock run faster, it can execute more instructions in the same amount of time. So there is an incentive to make the phone feel as fast as possible by cranking up the the clock frequency. But it turns out uh there's nothing free, no free lunch. And that applies to computation as well. And that phones are constrained and one of the obvious constraints is battery life. Yes, cranking up the clock frequency will let you do more instructions per unit time, but uh it also means that the computer is going to be doing overall more work per unit time, which means it has to consume more battery to do so per unit time. These logic gates at the end of the day that we're challen you can crank the clock frequency up, but it's going to eat at battery. So, there's a happy medium where you want to push it lower low enough where it's not uh too slow for the user. Um, at the point where we can try and maximize battery life for the phones. Um, but that's just something I wanted to call out. The other thing which isn't labeled explicitly here is our SAP used five clock cycles per instruction. More modern processors, including likely this one right here, even though it's no longer considered modern by any standard. Modern in the scale of computing. How about that? Um, they actually beat this. They can do one instruction per clock cycle. And uh I don't want to make things too confusing because this might not even be uh easy to wrap your head around, but a lot of modern processors can actually do multiple instructions per clock cycle. Um, so that's pretty interesting.

But let's continue and in and looking at the CPU itself. So um the first thing is that uh let's just read the start of the sentence. And there's a lot of tech like technical terms going on here. So I'm just going to read these first uh five or six words. The SL S5 L8900 contains a 32bit ARM V6 compatible CPU core. What does this mean? So, let's start with the 32-bit. Um, our computer that we built was an 8-bit computer, which means fundamentally every value we reason about is 8 bits. So, all of our instructions were 8 bits. The bus itself was 8 bits and every value in RAM was 8 bits. But we saw how this could be pretty limiting because it meant you had four bits to represent all your instructions, which is not that many different instructions. That's 16 different instructions. And then every uh instruction that took an argument used four bits to represent the argument which meant you were pretty limited in how much you could express. 32 bits uh is a lot more. So if I uh 2 to the 4 our our 8bit computer um had 256 different values it could represent. Uh, it's if we raise this to the 30 32nd power this is incomprehensibly large. Um, that would be 4 bill294,967,296 uh you know different values we can represent in in RAM alone specifically. Um, so a lot bigger. But then again, this might feel big relative to the computer we've constructed, which is 8 bits, but a lot of modern computers actually use more than this 64-bit architectures or 128-bit architectures. But as we saw with the case with um clocks, you might think like, hey, why would we not just try to scale this up and use as much as possible? But phones aren't just constrained by battery, they're also constrained by memory. So, um, if a a computer that uses 64-bit architecture versus a computer that uses 32-bit architecture, well, in a 64-bit architecture, each instruction is 64 bits. But in a 32-bit architecture, each instruction is 32 bits. So, with the same amount of space, you can represent twice as many instructions on a 32-bit architecture compared to a 64-bit architecture. So there's there's also this trade-off of like more higher bit architectures mean you can be more expressive and you have more data available or more memory available to work with but it also comes at the cost at like an increased cost of complexity. Uh, which pairs poorly with the fact that just phones are inherently constrained. Um, but what is ARMv6? Uh, and that's an interesting question. Um, let's Google it. So ARM Let's read this together. ARM is a family of risk instruction set architectures for computer processors. Okay. Well, so ARM is not a single instruction set architecture. It's a family of instruction set architectures. But what does this risk mean? Risk stands for reduced instruction set computer. And if we read the definition here, it's an architecture designed to simplify the individual instructions given to the computer to accomplish tasks. Um, and what this means is that a reduced instruction set computer might require more machine code to accomplish a task because the individual instructions perform simpler operations. So risk generally is something that you see a lot of uh phones or just resource constrained devices such as like embedded systems use uh because they're they're generally more compact uh but that also means they're less expressive and less powerful compared to to non-risk architectures. Um, but due to their low cost, let's jump back to the ARM Wikipedia. Due to their low cost, low power consumption, and low heat generation, ARM processors are useful for light portable batterypowered devices including smartphones, laptops, and tablet computers as well as embedded systems. So, ARM is very intentional. the architectures, the instruction set architectures that they introduced are specifically meant for resource constraint environments and they explicitly call out smartphones as being one such relevant use cases. Um, so if ARM is a family of instruction set architectures, let's see how many there actually are. If I scroll down here, you can see uh things obviously or things maybe you would have guessed started with ARM v1 and then we went to ARMv2, V3, V4 and it keeps going and these these keep coming out. I guess the uh I guess the latest is ARM ARMv9. Um, but these architectures, these instruction set architectures are all technically different uh but are somewhat related to each other and they're usually compatible. And the original iPhone uses an ARM v6 architecture. And this is the actual instruction set uh that the iPhone uses. So, this original iPhone, I guess just any of them, um, if you're running any application or doing anything, the code for, let's say, like if you were running Twitter on your original iPhone first generation, um, all the code that builds up the Twitter app is just a combination of ARM v6 instructions and as is the case for everything that your phone does. So all the code that represents the ability for you to send texts or make phone calls or uh browse the web all boils down to ARM v6 uh instructions. So you might think like hey like this must mean that like ARM v6 must have a ton of instructions and you know maybe there's an instruction to uh send an internet request out or an instruction to make a phone call. Uh, but it turns out when we actually look at the architecture uh we don't see any of that.

So what I'd like to do is actually take a stab and go ahead and look at the architecture. And I also want to keep things uh not too abstract. I guess everything we've done so far has been pretty abstract. I've showed you the computer we built, but we weren't able to verify that in the video itself because I don't have access to that old computer. Um, so what I do have is something called a Raspberry Pi Pico. And it is a small little microprocessor. It's like this. It's about the size of my pinky. Um, and something interesting about it is that its CPU also runs uh the same instruction set as the original iPhone. So this this also runs ARM v6. So, what I'd like to do is let's go ahead and take a look at the uh ARMv6 instruction set. It gets very complicated. Let's just take a poke at a high level and then let's actually write some code for ARMv6 and run it on this processor and and see if we can actually get some code to execute that does something that we can see with our own eyes. gone ahead and found the technical reference manual, which is pretty much just a guide for the processor that this Raspberry Pi Pico has. And um, just you can see how old it is. This was published in 2009, had two modifications, and hasn't really been updated since because we're on to much more modern processors, but this is still a great example. So, we're not going to go too deep into this, but I do want to poke at the instruction set. Um, let's start with the introduction about the processor. The Cortex M0 processor is a very low gate count highly energyefficient processor that is intended for microcontroller and deeply embedded applications that require an area optimized processor. So very low gate count. Gate count is literally referring to the logic gates that we use to build our computers. Generally speaking, the more logic gates a computer has, the more complexity and more battery consumption uh you can expect it to have. So having a low gate count is especially enticing for um these like constrained environments and that goes hand in hand with being highly energy efficient. Um, it is designed to use as little as little electricity as possible, which makes perfect sense for a phone. Uh, where, you know, especially back in 2008 when this first generation iPhone was released, uh, 2007, sorry. Um, discontinued in 2008. Uh, you know, you could imagine batteries, they're not even great today. Um, so they're quite quite worse back then. But, um, let's jump back to the docs. Uh, so let's look at this and see the instruction set summary. So let's read this. This processor implements the ARMv6 thumb instruction set. And ARMv6 is the architecture we saw earlier. And the thumb means that uh it's actually a even more compact. ARMv6 is already designed to be pretty minimal. Thumb makes it even more minimal by reducing a number of instructions that are always 30 32-bit on general ARMv6 architectures down into 16. So our computer had straight 8-bit instructions. This computer has a combination of 16-bit instructions and 32-bit instructions. And this is pretty interesting because our computer was designed to assume that everything we worked with was always 8 bits. But that's not strictly the case. Uh, this computer is a great counter example here. Instructions aren't always the same number of bits. They can actually vary. You could imagine some instructions that don't have any arguments or have minimal arguments need not use 32 full bits. Um, and so that's there's some use cases where we can get away with 16 bits or just fewer than 32 bits. Um, and if we scroll down, we can actually see the instructions. So, I'll just scroll all the way to the bottom. And you can see there's actually not a ridiculous number of instructions. I want to say there's like something around like 50 if I'm guessing here. And let's kind of comb through and see. So, ARM in general and I guess a lot of more just instruction sets in general operate with many more registers than our computer. Our computer had an A register and a B register, but really we only had instructions to operate on the A register. And a lot of the instructions that touch the B register were just to satisfy A register operations or things we'd like to do with the A register. Registers are really fast to access. As you saw, they literally just existed. you know, registers, you could literally put a value on the bus immediately or read a value in from the bus immediately versus RAM requires you to kind of put an address in the memory address register and decode that, which is just slower. So, RAM is still fast, don't get me wrong, but registers are even faster. So, for that reason, we generally like to work with registers just because they're really quick and easy to read and write from and don't require that much like clock that many clock cycles to do to interact with. So ARM has a lot more registers and they're general purpose registers meaning you can do whatever you want with them. Uh, but it just gives you more room for scratch work. So when we built our Fibonacci program we had a lot of intermediate values like we like to store the previous Fibonacci number and the the second to last Fibonacci number. And it would have been nice if we could have held those in registers, but instead we kind of had to keep on reserving spots in memory and writing those values to those addresses in memory when we wanted to update them and then reading them back into the A register when we needed to operate with them. Um, you can imagine if we just had more registers, we could just denote, hey, like this register will just for our program will always just hold the the n minus one number and this second other register will hold the n minus n minus2 number. Um, so a lot of what the arguments you'll see are actually operating on registers. So um, if I look at this add instruction uh it's saying you can pretty much add the values of two registers these two registers into the and it'll store the result in this third register. Um, or you can kind of see that this move instruction. It'll move the value from one reg from this register into this register. And that's kind of a bit of a different mental model. In our computer, we kind of only saw for the most part instructions being addresses and RAM. But here we're seeing that an argument can actually be just another register itself, like the the name of another register. Um, and then you can also see we still have some things that are similar. So like we had a load immediate that would load a immediate value into our A register where the value was encoded in the instruction itself. We still have that something pretty similar here. So you can see like this IMM just means an immediate and you can see that there's a register that you could want to load that immediate value into. Um, same same with some of our ads. So you could say, you know, add the value that's in a register, take that value, add it to some add some immediate value, constant value to it, and then store it in a destination register. Um, so you know, we can kind of see like there's move operations to move values from registers to other registers. You can see there's uh this one's interesting. Move any to PC. So the pro PC is per program counter as we saw earlier. That still exists here. We still have this mental model of the program counter tells us an address in memory and the computer will interpret that address and the value at that address in memory is an instruction and try to execute it. Um, so we have operations for moving data between registers. We have operations for doing addition. Similarly we have operations for doing subtraction. So you can kind of see like uh you can subtract um take the value in one reg in one register subtract it from another register and store store the result back into a destination register or you could have a immediate variant where you take the value in a register subtracted some constant value from it and write the result back into a different register or maybe the same register. Um, you can see there's like a you can negate values. There's also a multiplication. We never built multiplication in our computer, but the way we built the ALOU uh for handling addition and subtraction, you can imagine there's another component on more modern computers that can also do multiplication. What's interesting is this architecture does not actually have any support for division. So if you wanted to divide numbers, you'd actually need to write a algorithm using a combination of these instructions uh to to to get to to have division. you have to implement division yourself. Um, you also have instructions to compare the values uh in two registers or compare the value in a register to an immediate and this CPU has the same concept of flags. So the same way we had this jump zero and jump carry instruction on our computer that looked at the flags register that was determined based on the last ALU operation, we have something similar where you know there's flags and certain instructions can update the flags. We also have something called logical instructions which are like the logic gates that we designed earlier but they're actually instructions. Um, and we didn't have this in our computer. So let's take a look at this ands andds instruction. What this does is it'll take two registers as arguments and those are 32-bit values in each register because this is a 32-bit computer and you'll get a final value that it'll write into a different register. And what the final value is is also a 32-bit number where each bit position is the bitwise and of the two bits in the same positions of the operand argu uh registers. So uh the rightmost bit position in the output will be the rightmost the rightmost bit position of this register bitwise and with the rightmost bit position of this register. Um, and that's like the andgate and we have analogous versions for the exclusive or the bitwise or um, or even negation. Then we also have a family of instructions for shifting. Um, we haven't really talked about shifting so I'll kind of leave it alone for now but we'll actually see a program where it's kind of useful. Um, but pretty much you could imagine I can explain that like shifting uh if we had like some binary value uh 0 1 1 0 if we left shifted it once it would actually just shift all the bits over one to the left and then add a new zero. So we'd end up with 1 1 0 0 that'd be a left shift by one. Similarly if we started with a 0 1 1 0 and right shifted we'd end up with just 011 which is the equivalent of 0 011. So that's interesting. Um, and then we also have these load instructions which will let us load values from RAM into registers. And uh, what's interesting, we'll see this again shortly. The arguments could be literal addresses in memory or you could actually have that a value um, stored in a different register is meant to be an argument. And so you should take that argument uh take that register who is the argument go look up its value and treat that as an address in RAM. Look that up and then write that back into some other register. Um, so these are kind of our loads and you'll also see there's like there's some syntax differences here. So we have three arguments for this one. And uh pretty much what this is saying is it's saying take the at treat the value that's in register RN as an address and then add some immediate value to it. So maybe you want to like look two addresses after that. So you could add two and then it'll go look up that value at Rn plus two in RAM. Read that and write that into this register. Um, then we also have very similar variants for storing storing values in registers to RAM. Um, we have a push and a pop which we'll ignore for now. Uh, and then we also have branching. So unconditional just means you will always branch. So that's the equivalent of our just jump. You will no matter what the state of the computer is, you will jump to this other address. Then we also have conditional ones where you know you can imagine like there's like branch if two values are equal or branch if value is zero and that's kind of how we implemented our those are the equivalents of our jump carry and jump zero instructions. Um, and then we have a few more down here. And these are kind of a little bit weird like what is a supervisor call? What is an interrupt? Uh, what is an event? What is the concept of sending an event and waiting for an event? What is the concept of yielding? We have no op, which we already saw previously, which just does nothing. Um, and yeah, we're actually going to ignore these for now. Uh, there's no way to not look at this processor and see a ton of new stuff that we haven't already seen. But that's um this is this is more advanced and we're not going to probably get into it uh for the scope of what we're doing right now. But it is possible that a separate video will actually cover this specifically. So this is kind of an overview of the instruction set. You might be scratching your head where these instructions, yeah, I guess semantically they're a little bit different than what we built for our computer, but they're not that different. So like where is the instruction to you know write something to the display of the phone or something like that? And it turns out that there's just not an instruction for that. So you're probably even more confused now wondering well how does my the processor in my iPhone actually draw to the screen of the iPhone? And we're going to turn out uh we're going to do some keep poking this a little further. Turns out these instructions are actually capable of doing everything that we actually need to draw on the display or know when the user touches the screen at a particular location. And I'm going to jump back to my iPad and we're going to explain two concepts and then we'll jump back to the computer and those two concepts will actually start bridging the gap of how our processor can do things that aren't just mappy. Like everything we see right here is just kind of some variation of math or moving data. So we can implement very pure algorithms, but we're not seeing how we translate that to very practical things that we'd want a phone to do, like drawing a shape or, you know, showing some notification in a visual manner. Um, so let's go over the iPad. Uh, it's a little I don't mean to be very jumpy, but there are two different concepts that I like to explain. Um, and then we'll be able to jump back and actually write some code for our Raspberry Pi Pico.

Okay, so I'm back on my iPad and I said there's two concepts I want to teach you about. Number one is called Hex. So, uh, the instruction set architecture where we've been working with that we designed, uh, right up here was all 8 bits. You know, our bus was 8bit, our RAM was all 8 bits, all of our registers were 8 bits. Uh, but now we're looking at a 32-bit system. And binary totally works for 8 bits for saying, "Hey, our value is 1 0 1 1 0 0 just fictitious number." This works for 8 bits. It's fine. It's a little tedious to write out all eight bits, but oh well, we have to do it. When it's 32 bits, uh, that's a big pain to represent 32 digits for every number. And we'll see that not only is this pretty verbose, it's just not as readable. Um, the more ones and zeros you have chained together the the less the interpretate the interpret interpretability becomes. So instead of writing everything out in binary, what we're going to see as we look into this further and look at actual uh code for this architecture is something called hex. Um, hex is base 16. And recall from earlier uh we speak in base 10. And what this means is that there's 10 different values that can go into every digit position. And those are zero, one, two, three, four, five, six, seven, eight, and nine. Then we learned about base 2, which is binary. And two different values can go into this slot, zero and one. So I feel like if I told you about base 3, base 4, or anything up to base 9, you'd be able to reason about how to count and it wouldn't be that complicated. But when I'm saying base 16, this has some implication that there's 16 different values that could go in any digit position, but there's only 10 different digits that we know. Like every number we know is made up of of the the digits 0 through nine. So how can we represent 11 different digits, let alone 16 [snorts] uh if we don't have that many digits? Um, and it turns out we start using numbers. So, let's count in base 16 and see what it turns out, sorry, that we start using letters. So, let's count in base 16 and see what this looks like. So, we have 0 1 2 3 4 5 and everything up through nine is going to be the same. We'd like to write the number 10 here, but that is not onedigit position. That's twodigit positions. But we have to we're looking at single digit positions. So if we run out of every number, the next logical thing that we can use is other symbols. And letters are an easy symbol. We could start drawing shapes, but let's just stick with letters. So we're going to say A. And we sort of implicitly know that A maps to 10. And then B maps to 11, C maps to 12, D can map to 13, E can map to 14, and F can map to 15. And if we say that these are this is the set of digits in B 16, that is 16 different digits. Um, and it might be weird to reason about numbers and letters mixed interchangeably, but it pretty much means let's just look at an example of a a hex number. Let's say we have um a e this hex number and I'll also say for binary for for base 10 we just write out our numbers kind of we say like 762 the example number for binary uh we kind of prefix it sometimes with this 0B and then we say all of our binary digits. You'll see that for hex we prefix with 0x. So if you see zero x it means you have a hex number. So let's say we have ae. Well, uh we just need to figure out what the contribution of each digit position is to our overall sum. So if we were looking in base 10, we had the number 56. Recall that this is 6 * 10 ^ of 0 and then 5 * 10 ^ of 1. Um, so our analogous equivalent here is this is a * 16 to the^ of 1 plus e * 16 ^ of 0. And we know a is 10. So that's 10 * 16. And then we know e is 14. And 16 to the 0 is just one. So we have 160 and 14. when we add those together, it's just 174. So, this is not fundamentally too new from anything we've already seen, but I thought it warranted an example to show. Um, and yeah, pretty much that means that for example, if I just say 0x 9, that's still 9. But if I say 0xd, that's equivalent to the value of 13 in base 10. Base 10 being what we reason about as humans. So we can see that with a uh each digit in base 16 holds one of 16 different values. Which means if we think about this um we know that 2 to the 4 is equal to the^ of 16. So one hex digit equals four bits. you need four bits to represent discrete values for each of these uh digits in the vocab. Um, but this makes you makes things better because it means we have a 1 to4 mapping. So when our computer works with 32 bits, it's actually just eight hex digits. So every address in our computer is eight hex digits, which plays pretty well because that's the same number of digits that we had to to use to reason about our um our SAP computer. So that's concept number one. Concept number two is called MMIO. And I would actually say this is the crux of how the computer interacts with components that are not itself. So let's

Say that our computer, um, and this this Raspberry Pi Pico that I'm holding in my hand, which you can't see 'cause I'm screen sharing, has, um, an LED on it. So there's this CPU, and we know everything about the CPU. And then there's this LED. LED just stands for light-emitting diode. It's literally just a light. Um, and the question is, how could we possibly have our processor, with the instructions we know, turn that LED on and off?

And so, let's break down what MMIO stands for. The first M stands for memory, then mapped, input, output. So, MMIO stands for memory-mapped input output. What does this possibly mean? That doesn't put us any closer. Um, well, input-output is kind of this arrow here. In our case, we're just concerned about output. You know, we just, like we'd like our CPU to be able to, uh, turn the LED on and off. But who knows? Maybe this is, maybe we'd also like to be able to read if the LED is on or not. Uh, so there could be input. Um, and so I guess the crux of this is the memory-mapped part. And with the instructions we saw in the computer we built, and in the ARM V6 manual that we just combed through, there's no way to possibly turn on this LED or something that's just totally external to the processor itself. Um, and it turns out we use something called memory-mapped IO, which abstracts parts of memory to interact with third-party components.

So, we're just going to pick an a random address. Let's just say 0x. And I'm just inventing some 32-bit hex address. And pretty much what happens is, let's say you write a one to this value in memory, then it'll turn on the light. And if you write a zero to this value in memory, it'll turn off the light. And how could that be possible? Uh, it turns out the CPU is just designed. These these addresses are just determined arbitrarily. There's usually some consistency across, like, processors in the world. But, um, the CPU will interpret any attempt to write. So any storing of register value at, uh, any storing of a value to that address, um, instead of actually storing it to that address in RAM, it'll have a connection to this external component and it'll use that as the signal to go and turn on that component, like give it power or not.

So this is really powerful and I think very interesting, um, because it does mean that the, the implementation of the CPU has to be updated. But you can kind of guess how this would be done. You saw how instructions were decoded. So you can pretty much imagine that any storing instruction has some extra complexity now where it'll check, uh, you know, if you do some sort of store, then what happens is it goes one of two ways. You have to check the address, and it'll either write to RAM or it'll, you know, uh, connect to some peripheral. And we'll say operate on a peripheral. And a peripheral here just refers to any component of the computer that is external but still part of the computer as a whole, external to the CPU, um, something that can be interacted with via the CPU.

So in this hypothetical example, we'd say that if you write to this FFF AAA address, uh, a one will turn, will cause nothing to actually be written into that address in RAM. Uh, but it'll actually cause the light to be turned on. Um, or a zero will cause it to be turned off. And then we can just pick a different address. Uh, let's just say like FFF FF O. And we'll say that if you try read any read will give one if light on, zero if light off. So if we wanted in the CPU, in our program code, to know if the light was on, we would literally just load, we perform a load of this specific address in memory to a register, any register of our choosing. And when the computer sees that we are trying to access this specific address, it won't actually go look it up in RAM. It'll talk with the light component, figure out if it's on or not, and then put the corresponding value into that register.

So this is super powerful because it gives the illusion that we are just working with memory, um, but we're actually now using memory to interact with things that are not just RAM. We've kind of violated this assumption that we had previously where anytime we write or write, uh, a value to or from RAM, it would actually do some operation on memory. But this is not the case. In actuality, uh, only subsets of addresses, uh, will truly update RAM or read from RAM. And then plenty of others will be used to interface with external parts of the computer.

So if we explain, um, how this might look, so we know, you know, this is just one example of one specific address. Maybe let's say, uh, a display, a display on a phone, um, can maybe be broken up into a grid of pixels. I'm, I'm just ignore my dimensions here. Let's also, just for simplicity, assume that, um, each pixel, it's a black and white display display. So each pixel is either on or off. Then what we might do is say, uh, start with a specific address in memory. Let's say just hex, um, just this is maybe our starting address. And then our code would say, if you want to turn on this pixel, write on to this address. And then the next address, uh, in memory would correspond to the next pixel. So that'd be O O A1, and then this would be A2, and A3, and A4. So there'd be a like whole continuous chunk. If there's like, let's say there's 50 different pixels here, there could be 50 regions in memory, um, consecutive starting at this base address of hex A Z. And your code could draw an image or draw a line or anything by figuring out which of these pixels to turn on. So if it, uh, were to to write ones into the first five addresses, you'd see like a line appear at the top of your screen. And so that's how our our program code can actually turn on the display. Uh, so this is kind of how your phone display would work.

And then conversely, there could be, there's several different implementation ways to actually figure out when a user touches on the screen. Um, but perhaps one simple way is just the computer can decide some address. Let's say FF A621, just making up random addresses. And, uh, whenever your program code reads this address, it'll have, maybe encoded in there, the coordinates of the last place the user touched the screen. So you could constantly be reading from this address and see whenever it changes to detect if the user just touched the screen somewhere. Um, so this is what memory-mapped IO does. IO stands for input-output. It means pretty much communicating with the external world or other components that are part of this computer but not physically part of the CPU. And this MM, memory-mapped, is means that it it appears to the computer to all be under the guise of memory reads and writes. Uh, but in actuality, your processor is redirecting a subset of those around, uh, to accomplish this pretty neat behavior.

So this is super cool. Um, and unlocks the door to do a lot of things. You could imagine like, um, the CPU, you know, can now interact with not only a screen, but it might also have a, a some sort of, uh, separate processor, um, that has internet access. And then, you know, the CPU can now make internet requests. It could write, uh, the address of a, a URL in some register, and then this, it would get routed to the internet chip, and then maybe the internet chip could return some data about like what's at that internet address. So it's pretty powerful.

Um, let's actually write a program on the Raspberry Pi I have that will turn on an LED using memory-mapped IO. So here's the microprocessor I've been talking about for the past 20 minutes. And you'll have to bear with me because my computer webcam quality is not that great. But you can see this is the actual CPU. So it's analogous to what we just spent the past several hours building. And one of the other things to note is all these pins coming off the bottom. And, uh, a natural first question is like, what are these? So again, the, the image quality is just not great here. If I put this close to the camera, you'll see that they're all labeled. And many of them have the prefix GP and then some number following it. And what this actually is, these are GPIO pins, which stands for general-purpose input-output. So each of these pins, programmatically via memory-mapped IO, um, can either be used to read in data from that pin, either a zero or a one, or put out a value onto that pin, a zero or one. And this is using real electricity. So what I could do is take a specific pin, figure out what address in memory corresponds to controlling that pin, and then write a one to it. And then if I have like a physical wire right here, I could literally connect that pin and then plug this into a separate device. So maybe if I had like a light, I could connect it to to this other, the other end of this wire right here, and it would turn it on. Um, and there's more interesting things that would be if you wanted to use a pin for outputting. Maybe if we had a temperature sensor, um, or some sort of other device, uh, like a button or something that when pressed, we could read in that signal. Um, it all works with memory-mapped IO. So, in your code, even though you know that, hey, this pin's connected to a light or a button or a temperature sensor, uh, it appears as though you're just reading an address in memory.

And one of the more interesting things, um, that I just happen to have with me as well, is an actual display that, uh, has a bunch of holes for various GPIO pins to connect to. And there's some protocol which we won't get into here, but it lets you, uh, via memory address manipulation in the Raspberry Pi, write contents to a screen. So I have some text drawn on the screen here. Um, I'm building a subway tracker, but that's an independent project. And the code all exists on this Raspberry Pi, and it'll go to the internet, figure out when the subways are coming from my station. Um, and then by writing certain contents to various, uh, addresses in memory, it can actually, uh, cause, uh, text to appear on the display of the screen. So that's pretty neat. Um, so we have all these GPIO general-purpose input-output pins. And if I actually flip this around, there's one other thing that's pretty interesting, and it's this this copper-like thing up here. And above it, it says LED, which stands for light-emitting diode. And this is just a light that we can use to turn on and off in our code however we want. Um, it's nice because we could, you know, write to a wire and then have that wire connect to a light. I just don't have one. So, this computer, this microprocessor, sorry, conveniently has a light built in. So, what we're going to do now is take a peek at figuring out how we can get code to run on this, um, that would turn on the light. And then the last thing we need to bridge is that there's this USB port right here. So that's how I can connect it to my computer and actually get code that I have on my computer, machine code binary, uh, onto the device. It's a pretty intricate process in itself, and we're not going to concern ourselves too much with it here. Um, but it is worth calling out, like, if I'm typing code on my computer, how do I actually get it onto this microprocessor itself?

So, let me go ahead and tab back to my computer. So, back on my computer, and I'm actually going to start with the solution. And I will claim that if you run this set of instructions on your computer, on this processor that I'm holding in my hand, it will boot up the computer and turn on the light. Um, so let's take a look at what this is. These are various addresses. Recall that the computer's 32-bit, uh, addresses. And so these are actually hex addresses because they're more compact but equally as representative. So two, three, four, five, six, seven, eight. Eight hex characters in each address, where, you know, each hex character represents four bits of data, means 8 * 4 is 32. So these are equivalent to 32-bit addresses. So that's consistent with our expectations. And then what we have right here is the literal value that is stored at each of these addresses. And it's also again in hex. Um, but this is a little uninterpretable because it's, we know the binary, uh, is not necessarily intended to be interpreted as a number, but rather as some instruction that encodes an operation with some possible arguments. Um, so there's semantic meaning outside of the digit, uh, numerical interpretation. And that's exactly what we have over here on the the right column. We have, uh, a bunch of, uh, instructions. So we haven't seen any of these instructions because we only skimmed through the, uh, instruction set architecture, but we'll give some motivation as we walk through these. So you can see like, this is an instruction, LDR is an instruction, BIC's instruction. You can see R1, and R2, and R3, and so on, are all different registers that we have accessible to us. Some things look familiar, like PC, we know is the program counter. Um, and then these are all instructions. We can kind of see down here, uh, where it says this word. We'll see this shortly, but these are actually used to store values. Um, so the same way in our Fibonacci program we stored values in certain addresses in RAM, we do the same thing here because sometimes an instruction can't be, uh, with as many bits as we have, can't represent a full opcode and a 32-bit argument, uh, in the constraint of a 32-bit instruction itself. So we'll see similar tricks where we store, uh, addresses in certain addresses in certain positions in RAM or arguments that we can't encode instructions themselves. Um, but if I ran this on the computer, it wouldn't be that satisfying because we haven't really explained what we've done. So there's two questions. Um, one is, what is this code doing? And two is, if we understand what the code is doing, how did I know to write this code out? And to answer those questions, I actually turned to the, uh, documentation for this processor. And at a brief glance, if I look at the table of contents and scroll all the way to the bottom, we can see this is 640 pages. So this, um, pretty small processor somehow has a lot of complexity going on, uh, to justify that much documentation. And it turns out this is a pretty feature-rich chip. And we're only going to touch this, scratch the surface here. Um, but this documentation has explains everything we need to do to actually turn on the LED we're interested in.

So, I'm not going to read everything in too much granularity here, but what I will do is jump around the various sections. So, the very first thing we need to do, um, if you read this, is come over to this chapter and let's read this. "The reset controller allows software control of the resets to all peripherals that are not critical to boot the processor." Um, and this is a lot of jargon. What this means is that when we turn on the computer, uh, only a subset of functionality is enabled, and that subset of functionality is exactly what it needs to get the computer booted. You can imagine that that LED is not necessary for it to start up. So most external things that aren't strictly necessary for the computer to get running are actually turned off by default. So there's a, um, particular address in memory that we can write data to that will let us turn things on. So the first thing we need to do is tell that our processor, like, hey, we actually do want to interact with these GPIO pins. Um, and we can see that the documentation says three registers are defined, and there's this reset one. "This register contains a bit per each peripheral that can be reset. If the bit is set to one, then the reset is asserted. If the bit is clear, then the re, the reset is deasserted." So what this means is we have a 32-bit register somewhere. Some address in memory can be interpreted as the address by which we can interface with this register. And each bit position in that 32-bit value lets us turn on or off some peripheral. If I actually come up here, I can see the one we're interested in is IO bank zero. Um, that's just me telling you. You wouldn't have known that on your own without more reading of this documentation. And you can see it's the, uh, fifth bit position, um, from this this reset register. So, we'd like to figure out where the reset register is in memory. And if I scroll down here, um, we can see that it says the reset controller registers. So there's several registers. The one we're interested in is just the reset one. Start at a base address of this hex value. And then we're interested in this reset. So it says offset 0x0. What this means is that you take the base address and add an offset, and that gives you the true destination address. In our case, we're adding zero. So it means the reset register is quite literally at this address. If we wanted to interface with this reset done register, we'd look at offset hex 8. So we'd add hex 8 to this value, and that would let us interface with this reset done register. So the very first thing we need to do is write to this reset register and, um, set the bit position for IO bank zero, which is the fifth bit position, set it to zero, and that'll let us tell the computer that, hey, like, we actually do want to do some IO.

So let's jump back to the instructions and see what the first few set of instructions are doing that let us accomplish this. I'm going to tell you what each of these instructions does. Um, this very first one, MOV S, is moving a literal value of 32 into the register R1. So after this instruction runs, register 1 will have the literal value 32. But let's actually spell that out in binary. Uh, so we can see why that's happening. So this is 32 in hex. Um, and the reason 32 is interesting is because where we see, uh, what we see is all the bits are zero except one. And that one is actually the fifth bit position from the right. Uh, which is interesting because we know that we needed to eventually find some address in memory, uh, of this resets register and set that specific bit position, uh, to zero. So that's just a little hint at where we're going. So after, uh, this first instruction executes, this is the state of the machine. The next instruction, um, is LDR, which stands for load a value into a register. And we're loading a value into the register 2. And where, what the value we're loading into is actually what, uh, whatever the program counter plus 36 is. Look at that address in memory, um, and get the value from there. If we do the math, the program counter, because we're executing this instruction, has to be at this address. So if we add 36 to it, uh, we get this address right here. And if we come down here, we actually see that that corresponds to this address right here. And this should look very familiar because that is the base address of the reset register. So that's the value we actually want to, uh, write into. So if I copy that, then the state of our computer. Oops. Um, after the first instruction, I've done something wrong here. I've gone to a weird state there. Um, fix this up. So, R2 now holds the address of this reset register, uh, where it's memory-mapped to. The next thing we actually need to do is read what the value in is. And so that's exactly what this next instruction does, where LDR says load into register 3 whatever, uh, the address in register 2 points to. So register 2 points to the address of this this resets register. So we're actually going to load the contents of that register into R3. So R1 and R2 are the same after this command. R3 is going to look something like this. It's a 32-bit value. We don't really know what each of the bit positions are, except for the fact that we do know that since the, uh, this LED is turned off at boot, um, this fifth bit position right here is going to be a one. And what we'd like to then do is actually rewrite that value, um, keeping every other bit position the same but flipping this one to a zero. And so that's exactly what this BIC instruction will do. Um, it'll say this is the bitwise AND of register 3 and the inverse of register 1. So let's break that down. Um, let me go ahead and, we know that register one has this value. The inverse of register one would be if we flip every zero to a one and every one to a zero. And so that looks exactly like that. And then we are doing, um, a bitwise AND with register 3. So what effect would this have? Let's just think about this reasonably. We said that register 3, register 2 and register 3 are still the same. Um, register three, I'm just going to move this out of the way so we can look at these next to each other. Register three, we know that we don't really want to change the values in any of the bit positions. So a bitwise AND of any either a zero or a one with a one is just going to return the same value that's already in X. So in every place that we are bitwise, bitwise AND an X with a one, it's just going to remain the same. The interesting thing is this fifth bit position. When we bitwise AND it with zero, it's actually just going to turn off that one bit position because anything AND zero through a logic gate is necessarily zero. So R3 becomes this register where every bit position is unchanged except the fifth posit, fifth bit position becomes a zero. And that is the value that we'd like to write back into this address in memory to tell our CPU, hey, we actually, uh, are we actually do want to interact with these GPIO pins. And so we've constructed the value that we'd like to write back, and it's in register 3. But we actually need to write it back to this address in memory, uh, for it to be usable. And that's what the next instruction does. It says store, um, the contents of register 3, I.e., what we'd like to write into the resets register, into the address held by register 2. And this is saying you can just add zero to it. So it's just the same as not specifying anything. So what this will then do is actually, um, write this value, this binary value, into the resets register. And so we've, if we jump back to our docs here, um, we can see that, you know, if the bit is set to one, then the reset is asserted. If the bit is cleared, i.e., set to zero, then the reset is deasserted. So now this means that we've written this value back in and have turned off the fifth, fifth bit position. It tells the computer that we actually do want to use IO bank zero. So that's our first step done. And I'm actually going to clear out all the instructions we've seen until now, just to keep things cleaner. Um, so we've made sense of those instructions, but when we tell the computer that we want to turn on IO bank zero, it actually takes some time to do so. And so we need to wait until the computer fully acknowledges our request before we try to write to the LED. If we simply wrote this value of saying, "Hey, I want to use IO bank zero," and then immediately turned on the light, it might not actually work because the computer needs to do some stuff to actually enable IO bank zero. And so if I come here, there's this reset bit, reset done register, and it's the same structure where it says there's a bit for each peripheral, except the difference is that it gets set once the peripheral is out of reset. And there's an explicit comment that says, "This allows software, i.e., the bytecode that we are writing, to wait for this status bit in case the peripheral has some initial initialization to do before it can be used." So in our specific case, there is some stuff that needs to happen before we can just use the, uh, the LED. So we need to wait, um, for the bit position five in this reset done register to tell us, uh, that it gets, that it, we are safe to proceed.

So the next question is, where is this resets done register? And if we scroll back up, uh, oops, or maybe it's down, um, we see that it is right here. We get the address. So it starts at the same base address that the resets register is at, but this time it's hex 8 further away from, uh, the base address. So now we'd expect the, uh, the address of this register to be 400C 008. And if I tab back to our code, we can see that that is exactly somewhere in memory. Uh, that address is stored somewhere in memory. So we can probably expect our code's going to try, uh, try access that address in memory. So let's go ahead and do that. Um, let's figure out what this next instruction does. This next instruction says, uh, we are going to load the same fifth bit position mask into R2. So that's the same little cheeky hack we did to get every bit zero except this fifth position index. Um, because we're going to do the same thing where we actually try wait and keep reading for that fifth bit position in this new register to figure out when it becomes a one. And then we're going to see that we're going to load, uh, our next instruction says load into register 1 whatever is 28 memory addresses below this current one. And that is actually right here, which is that exact address of this register that we're interested in interfacing. So this is the address of the reset done register. Then what we do is we actually, that's our register one has the address that we need to read from memory. So we actually need to go read that value from memory into another, into another, another register, sorry. So that's what our next instruction does. It says load into register 3 whatever the contents is at the address held in register one, which is just the reset done register. And that will look something like, we don't really know. It may or may not be done by the time we read it. So we can say maybe it looks something like this, um, except this one right here could be a one or a zero. So I'm going to write it as a question mark. We don't know if it's going to be done or not. And so the next thing we need to do is actually read that fifth bit position and figure out if it's, if it's one or zero, because if it's one, that means we are initialized and we can actually turn on the light. Otherwise, we need to wait and check again. So this TST instruction, um, is what will do that, and it's called test bits. It'll do a bitwise AND between the two arguments. In this case, that's register two and register three. And similarly, it won't spit out a value, but it'll set flags. The same way in our CPU doing an addition wouldn't, would it would spit out a value, but it also implicitly update the flags register. This CPU architecture has the same thing where it has its own concept of a flags register. So we already know that, um, bit like R2 bitwise ANDed with R3, it's either going to be zero if the, um, if the LED is not ready, or it'll be one, um, if it is ready, because this question mark would be a one. So one bitwise ANDed with one would imply that it is turned on, one if ready. So we make that comparison, and then this branch, this, this next instruction says BEQ.N, and this pretty much means if the, if the bit was a zero, i.e., if the output of the last instruction was a zero, we aren't ready yet. So we need to branch, um, back to this address right here. So pretty much, we'll check what the output of the last instruction was, and if it is a zero, then we will jump to this address right here, which is actually the one we just came up from right here. So if it is zero, what it'll try to do is actually just read that same register again and do the same bitwise AND check. Um, and if it is a one, then we just fall through this instruction as expected, and we end up here. So pretty much, what this effect has is it'll keep checking the value of the reset done register until it spits back a one, which means at this point that we reach this, uh, this code right here, the the LED is ready to use.

Let me go ahead and now clear out this code since we know what it does and we're getting near the end, but we still haven't done anything to turn on the light. Um, and so now that we've told the computer that we actually want to use the GPIO pins, we need to go tell the computer how we actually want to use the LED specifically. So the LED, if you read the documentation, corresponds to GPIO pin number 25. And there's several different ways to interface with the GPIO pins besides reading or writing values to them directly from code. But we aren't going to get into that in this video for the sake of our video. All we do want to be able to do is read and write values to these as if they were just addressable regions in our RAM. So we need to go tell the code that that's exactly how we want to use these. That is called SIO. Since we're single cycle IO, um, and it's required, we need to tell the CPU that for GPO, GPIO pin number 25, we'd like to be able to interface it with SIO, single cycle IO. And that'll just pretty much allow us to get the remainder code running that lets us write, uh, to a particular address in memory to actually turn on the LED. So I'll jump back to the documentation and we'll see that there is a, uh, a register called GPIO25 control, and it is a control including function select and overrides. So, uh, again, I'm not going to spell out how I knew to do this, uh, just for the sake of time, but we pretty much just want to write the number five into this register, and the system will interpret that number five as, uh, SIO. So we need to figure out where this register lives in memory. And we can see that, uh, the user bank IO register starts at this base address. And then R number 25 has an offset of 0C8, or sorry, 0cc. If I jump back in the code, coincidentally enough, this address lives right here. So we'll probably expect our code to, uh, to do that pretty, pretty to read that, uh, specific address in RAM pretty shortly. Let's keep tracing what this does. So this will load, uh, the first instruction will load the literal value five, um, into R2, because that's the value that we'd like to write into this register. And then the next instruction will load into R3 whatever the value in RAM is at program counter, i.e., current instruction plus 24, that turns out to be this address that ends in 304, which is the address that we just identified of the specific GPIO25 controller. So that's what R3 will look like. And then the last thing we do is we'll say store, write whatever is in R2. So write the number five to some address in memory, and that address in memory is held in the value of R3. So this will actually do the writing, write five into the GPIO25 control line. And so this will now tell the computer we intend to use, uh, this GPIO25, which is the LED, um, in the normal, quote unquote, way of being able to read and write from it as if it was just random or specific addresses in memory.

So let me go ahead and clear that code out. That the IO and GPIO stand for input-output, which means that each of the pins can be used to either put in, put out a value. So write a logical one or a logical zero, or it can be used to read in a value. So if it's connected to some circuit that outputs a value, it can read in a logical one or a logical zero. In our case, we need to specify that, um, the computer doesn't know how we're going to use each pin. So, we need to go tell it, hey, for this GPIO pin, we're going to use it either as input or output. For GPIO 25 specifically, that is the LED. We know that it can only be used for output because it's literally connected to a light. So, we can either turn that light on or off. But for consistency with how every other GPIO pin works, we need to go tell the, uh, processor that we intend to use use it as output. So if I jump back to the docs here, there is this register, um, GPIO output enable set. And if I jump into it, uh, it kind of gives this implication that, uh, it's similar to the previous registers we worked with, where it's one register and each bit in it corresponds to one of the GPIO pins. So in our case, we need to go ahead and tell, uh, the 25th bit position, i.e., the bit position that corresponds with GPIO number 25, that we intend to use it as an output. And we do that just by writing, um, writing a logical one to it. And so we need to figure out where this register is. We can see they started a base register of hex D followed by a bunch of O's. And then this specific one ends with has the offset hex 024. So if we add those together, we'd get D 000000 several zeros and then 24. So, if I jump back to code, I can see that that address lives right here. And what I'm actually going to do is come down here and clear out these three addresses because we're not going to read them anymore. The code that that used them once has already been executed. By the time we get to this top instruction, we know that we're not going to read those values again since we've accomplished what we needed to. What we will do, though, is load, um, 128 into R3. So if I do that, this is what the binary looks like. Notice that there's one bit position on followed by seven zeros. We're not done with this. Uh, it kind of is an arbitrary value for now, but we'll come back to that. Then what we'll do is we'll load into register 2, um, whatever address is hex 20 below what we're at right now, which corresponds to this address ending in 308, which is the address of that GPIO, um, output set register. Then what we'll do is we know we need to turn on the, uh, 25th bit, but right now the bit mask we have in register R3 corresponds to the, uh, seventh bit. There's notice how there's seven zeros after here. Um, so we end up doing is we want to left shift this content. I left shift means, um, chop off a zero at the end and move it over to the right. We want to left shift 18 times. And that's exactly what this instruction right here does. It'll say, "Hey, take register R3, its contents, left shift them 18 times, and then write that result back into register R3." And so if I copy what R3 looks like after, and R2 is unaffected by this instruction, we can see that, um, this actually is masking the 25th bit position, uh, the one that corresponds to our GPIO number 25. And so what we end up doing in this next instruction is storing the value in R3 into RAM at the address specified by R2. So this writes into this, um, GPIO outset register. And so now we've told the computer, hey, we want to use this specific register for output, or this specific GPIO pin for output. The very last thing we can finally do now is actually write a one to that pin so it'll turn on the light. So what we need to do is jump back to the docs. And the register we actually want to write into is this GPIO outset. And the structure is pretty much the same where each bit position corresponds to a GPIO pin. In our case, the 25th pos, 25th bit position corresponds to the 25th, um, GPIO pin. And if we write a one to that specific bit position, it'll turn on the LED. So, oh, the last thing we need to do is figure out where the address of this register is. We see it has the same base address of hex D followed by zeros. And then in this case, the offset is hex 14. So, we'd expect the, uh, address to be D some number of zeros ending in 14. If I tab back, that's exactly what this address and, uh, this this value and this address has right here. So we see we in our next instruction, we load into register 2 that specific address, uh, hex 20 below where we are in the program counter. And then that's all that instruction does. Then this store, uh, does the same write of this bit mask. And I apologize, I deleted R3, but it actually never changed from the code above. So I'll add that back in. It'll store the same value that just has a 25th bit position set to the address held in the R2 register, which is specifically the GPIO out set, um, register. And so what this will actually do is after everything we've done, it'll actually finally go ahead and turn on the light. But after we do this, the computer's trivial, or I guess naive is a better word, in the sense that it executes this instruction. We want to end the program here, but the program counter is just going to increment and keep executing what comes below it in memory. We want to halt our program effectively. Just leave the LED on. So, this last instruction we have, I'll delete these two since we don't need them, um, is just a branch, an unconditional branch, meaning it'll always just branch, no matter what, uh, to this address right here. But this address is the one we're executing. So pretty much all this line will do is keep jumping to itself, which means the program counter can never make it further than what we're at. Um, which effectively is a halt. The code can never make it to any other instruction in memory. So, what will happen if we put this computer, this program on our on our little microprocessor is it'll set up all the initialization needed to turn on the LED. It'll turn it on and then it'll get stuck on this instruction. So, as long as it has power, it'll never do anything else.

So, what we can go ahead and do is actually put that program, um, onto the computer. And let me switch back to my camera and let's see how it runs. So, I've gone ahead and installed the program on this, uh, microcontroller. I'll skip the part of how I actually installed it because, uh, it's a pretty interesting side discussion, but unfortunately, with the timing constraints, I'm not going to be able to get to it in this video. But what I should expect, if the program we built is fully correct, that as soon as I plug this in via the USB port and give it electricity, the only thing that we should be able to perceive with our eyes, there's a lot more going on. We obviously can't see instructions getting executed, um, in the same way we could with the old computer because it's, it's just so much smaller and there's not like all these these lights for our human interpretability. But what I would expect is the LED right here that you can't see that well, that copper-looking, uh, circle should just turn on. And that's all that should happen. It shouldn't turn off. It should just turn on. Um, and so I have power. Let's go ahead and do that. I'm going to go ahead and plug it in. And you can see, uh, it just turns on. And if I unplug it, it kills power to the program. It's done. Obviously, it can't turn on the light without electricity as a source. But if I plug it back in, it should rerun the exact same bytecode that we programmed onto it in the past half hour. Uh, which means that the LED should just once again turn on. And this is cool. The computer will hold the program forever until it's rewritten. So no matter what power source I connect this into, as long as it gets electricity, that light will just turn on. Obviously, this is a pretty trivial program. Um, but we could make this more interesting. For example, let's say we wanted to blink the light. How would we update our program to do that? One natural way is just pretty much, we know how to turn it on, and we know how to turn it off by writing a zero to that same register effectively. Uh, turns out there's actually a separate register, but that's a separate discussion. Uh, the the concept is fundamentally the same. What we could do is just load a value, a really large value into a register and keep subtracting it down by one, and then once it gets to zero, turn off the light, and then start the same cycle, uh, the same sequence where you load a really high number, count it down to zero one at a time, and once it hits zero, turn the light back on. And the computer, I mean, it runs at a pretty fast clock speed, but if we're dealing with very large numbers, counting down by one will actually take hundreds of milliseconds, um, which means that it gives the illusion of this light blinking. And pretty much changing that number from lower to higher will mean that the, it'll slow down the blink cycle, and if I make that countdown number lower, it'll make it blink faster and faster. Um, so unfortunately, we just got around to looking at this computer, and there's a ton of interesting stuff we can do. If I had more time, I would have loved to continue playing around with the GPIO pins and see how we can interface with external sensors or even write, you know, text to a screen as I've done here. But, uh, unfortunately, I'm bounded by YouTube's 12-hour upload limit. Um, and so this feels like the best stopping place I could reach for this video.

I wanted to take just a little bit to recap everything we've done. Uh, on one hand, we culminated nearly a 12-hour video with just turning on a light. Um, but the more you know about it, the more you realize, like, that's a trivial way to look at things, and there's actually so much more happening under the hood. So just as a recall of everything we've done, we started off looking at binary. Uh, humans reason in base 10. We have the digits 0 through 9. Computers only have the presence or absence of electricity. So we dumb our, we dumb it down to base 2, which leaves the only digits available to us zero and one. But it turns out this is just as expressive as decimal. Any number that we can interpret as humans can be converted to binary and vice versa. There's a one-to-one mapping of decimal numbers and binary numbers. Once we had binary understood, we started looking at logic gates and how we can make decisions by chaining logic gates together. And then we started looking at how we could store data. We built the concept of a flip-flop and a register. So rather than a circuit just taking some inputs and yielding an output, we could actually hold in a value. And then we started figuring out how we could chain both of these ideas together to build more interesting things. We started off by building registers and then RAM. Um, we also built an ALU. We built the ability to add and subtract binary numbers using just logic gates. And then we chained it together, uh, by adding a bus, throwing in more registers, and then the ability to interpret, uh, instructions or values in memory as instructions, and then physically with more logic gates in a read-only memory, execute those instructions sequentially. And then once we had that, we looked at a more modern processor, which is, uh, not too dissimilar from the original iPhone, and saw how we could, we looked at its instruction set and then also saw how we could write programs for that computer.

And, um, if we had more time, what I'd like to look into next is a few things. Number one, how can a computer actually write to a display? I think you have a high-level understanding, but we didn't get to see it in practice, so I think it might be a little bit confusing. Number two is, what actually happens when you power on a computer? We said that RAM's kind of initialized as all zeros or random memory. So how is a program physically stored on this chip, and how is it such that when we actually give the computer power, it just starts executing that program? Turns out there's a several really interesting things that happen early, and this is called like the boot sequence. Um, and the third and last thing that I'd like to look into if I had more time in this video is how computers run multiple programs at once. Your computer, you can multitask. You can have a video playing, um, while texting someone, while browsing the web. And, uh, the computer we've architected here can only run one program at a time. Um, but computers have this clever little trick that actually allows them to, uh, give the illusion of running multiple programs at once by quickly swapping between separate programs, uh, in quick succession so they each get a little bit of runtime.

Um, this video ended up being way longer than I expected. I'm not sure if anyone will ever watch it, but it was awesome for me to make this. I am sure there's some gaps in parts of the videos. It's my first time doing something like this, so if there's any questions, um, feel free to leave a comment. I promise I'll monitor the comments and respond to anything that's ambiguous. And, uh, if time permits, uh, maybe one day I can get around to making a follow-up video if there's, uh, any number of people that actually watch this and have interest. Um, I don't know if I could do a whole another 12-hour video if no one's going to watch it. But yeah, uh, thank you everyone, or anyone is probably a better word, who made it this far. And I hope you learned something. This was probably the most interesting part of my computer science degree, and I think a lot of software developers out there don't have a good enough understanding of what's happening at a low level. Um, but to take something that's very like foreign and actually break it down and see what's happening down to the flow of electricity is very powerful. And now you know that, uh, this computer I hold, and most computers that you interface with, are nothing more than logic gates chained together in very interesting ways to manipulate electricity to do very interesting things. Um, yeah, thanks everyone.