this video was sponsored by brilliant to run programs computers follow instructions step by step but that doesn't mean they always execute instructions in a strict sequence to be useful computers must be able to make decisions and repeat steps in today's episode we'll explore how computers handle conditions and Loops hi friends my name is George and this is core dumped before starting a quick reminder you can find me on social media let's start with a quick recap of how CPUs run instructions when we write programs we typically use programming languages that computers cannot understand this is
why compilers exist a compiler is a program that takes code written in a programming language and translates it into something else usually an executable file it is a common misconception that an executable file is just a list of CPU instructions but it also contains the data that our program needs to accomplish its purpose consider the example shown on the screen here the numbers 20 and 100 are values that our program will need at runtime so the compiler must include those values somewhere in the executable file to run the program its executable file is loaded into
memory allowing the CPU to begin fetching instructions from it remember a processor is connected to Ram from which it can read and write all sorts of information including both instructions and data running an instruction involves passing through three stages first the CPU needs to read the instruction from memory to do this the content of the address register sometimes called the program counter is sent to the memory's address input while the read enable signal is activated this causes the memory to Output the content at that location which is then written into the instruction register of the
CPU this stage is known as the fetch stage next the control unit reads the content in the instruction register to interpret the instruction or in other words to determine what action the CPU should take next this is known as the decode stage and once the instruction is decoded the control unit sets everything up so that the instruction can be executed in this example it loads the content from memory location 5 which is the number 20 into register Z this is known as the execute stage finally after the instruction has been executed the control unit increments
the value in the address register this is done to ensure that when the CPU returns to the fetch stage it will retrieve the instruction immediately following the one just executed our example program requires four different instructions like the first instruction the second one also retrieves a value from memory into the CPU this time from memory location 6 into register 1 again right after executing the instruction the value in the address register is incremented the third instruction is fetched but this time it's an arithmetic operation decoding this instruction tells the CPU to add whatever values are
currently held in register Z and register one and then write the result back in the register that contained the first operand and again the program counter is incremented note something important the add instruction wouldn't make sense without first loading into the registers the values we want to add in our example program we don't just want to add two numbers we also want to store the result in a variable when we assign values to variables it's because we want to access those values later using the variable name in other words to remember the value translated into
low-level terms this means the result must be stored in memory so that we can retrieve it later if needed that's exactly what the following instruction does the store instruction directs the register to send its value to memory specifies an address and activates the right enable signal this tells the memory that we want to write a value to that location instead of reading from it and just like that our result is now safely stored in memory location 7 at this point our program should be complete however the CPU itself cannot differentiate between instructions and data to
prevent it from mistakenly fetching data as if it were more instructions to execute a special instruction is added at the end this instruction tells the CPU to Halt ensuring it doesn't continue running unnecessary operations now now let's modify our program by adding a new line of code the instructions for the first line remain almost the same except for the addresses I'll explain this further in a moment the second line also involves an addition so the operands need to be loaded into registers the first operand is the value of the variable a the second operand should
be the number one then the addition is performed and the result is saved while this approach is valid we can optimize it but first a quick message from brilliant on the this channel we love learning in an intuitive way rather than endlessly reading PDFs that's why brilliant is designed for you brilliant is a learning platform designed to be uniquely effective their first principles approach helps you build understanding from the ground up each lesson is filled with Hands-On problem solving that lets you actively engage with Concepts so you can learn by doing rather than just reading
brilliant helps build your critical thinking skills through problem solving not memorizing and remember being a good problem is what differentiate good from average programmers you can start your Learning Journey with courses like thinking in code creative coding programming in Python and even more advanced topics like how llms work you can get a 30 days free trial of brilliant premium and get a 20% discount on your annual subscription if you sign up using the link in the description below first we could use a special instruction from our architecture that allows us to increment the value in
a register without loading the the number one into another register next remember that the value of the variable a was stored in register zero when the previous Edition was performed as we haven't loaded anything else into that register since then the value of a is still there making the load instruction unnecessary there are all sorts of clever tricks to reduce the number of instructions needed to run a program and compilers do it all the time I'm considering making a video on basic compiler optimizations so make sure to subscribe our compiled program would look something like
this but as I mentioned before there's a small issue with the addresses for example the first two load instructions should load data but since we added more instructions the values 20 and 100 are no longer in the same memory locations as before so we need to ensure that we provide the correct addresses the same issue occurs with the store instructions an old but good trick to simplify this process is to place instructions at the beginning of memory and data at the end given that our architecture is very limited with only 16 Ram locations available our
program will end up looking like this modern architectures handle this in different ways but that's not the focus of this video to run this program we load it into memory from this point onward instead of manually animating everything I'll use a small program I coded this would allow us to to visualize data in different formats so it is easier to understand just remember that in actual Hardware everything is still ones and zeros running our program will look something like this this is fundamentally how computers run programs it's all about moving data from memory to the
CPU manipulating it in some way and then storing the result back in memory executing one instruction after another this approach makes sense because when we write programs even in higher level languages we still write them step by step or line by line but we haven't yet considered conditions and Loops the ability to do one thing or another depending on the situation or to repeat steps is actually more critical than many people realize in fact without these features computers would be extremely Limited in the tasks they could perform we'll discuss touring completeness in another episode for
now let's focus on how computers handle conditions and Loops we'll start by manual compiling a program what we have here is an infinite Loop in the first line we initialize a variable with the number zero to do this we need to load the value into a register and then copy it to the memory location where the variable a will reside for the line inside the loop we need to perform an addition since the most current value of the variable a is already loaded in register zero we don't have to load it again so we can
immediately use an increment operation to add one to its value but we're not just adding we're also updating the value of variable a with the result of this addition so a store instruction must follow but we need this process to repeat indefinitely this is where the jump instruction comes into play as you can see this instruction has a memory address as its name implies its sole purpose is to make our program jump to that location since it is making the program jump to a previous instruction at some point the program will reach the jump instruction
again the halt instruction is there of course but it will never be reached because the jump instruction makes the program return to a previous step if you're wondering how this works internally it's actually very simple jump is just a term referring to the effect of executing this instruction what this instruction really does is tell the control unit to overwrite the content of the address register with the provided value so is similar to the load instruction but we are writing to the address register instead of the general purpose register by doing this instead of incrementing the
value of the address register the CPU fetches an instruction that is not the next one in sequence which appears to us as if it's jumping and that's how we Implement an infinite loop at the hardware level although this is cool jump instructions are limited because well they always jump but what if we need to jump only if certain conditions are met before answering that I need to talk about Flags let's run a simple program where we subtract a number from itself nothing new here we load the number 12 into a register subtract this value from
itself and then save the result in memory now let's run this program the result is obviously zero but did you notice something what are those little squares anyway those squares are one bit registers called Flags every time the ALU performs an operation it doesn't just output the result it also provides extra information about the result when any of these flags is set to one the ALU is notifying us that the result of the operation has either overflowed is zero or is negative since the result of our operation was Zero the ALU is notifying us about
it or for example if we run the infinite Loop program we'll notice that when the variable a reaches the value 255 incrementing it causes the Overflow flag to turn on for those unfamiliar with these Concepts this happens because the number 256 is represented by a binary sequence that can no longer fit in one bite of information here's another example if we subtract a larger number from a smaller one the result will be negative and the negative flag will notify us of that but why would the ALU highlight these kinds of results the reason is simple
it allows our program to use this information to make decisions this is where I can finally introduce you to conditional J jumps the way these instructions work is by jumping to the specified address but only if certain conditions related to the state of the flags are met that's the best way I can explain these instructions in general terms I suggest taking your time to review this slide as we'll use these instructions in the following examples let's create a while loop but this time we'll add a condition so it won't run indefinitely once again we're going
to manually compile this program the first line of code in involves loading a constant value and storing it in the address where a variable resides but this time we can't just start executing the lines inside the loop and then jump back because now we have a condition to check now think about this whenever we want to compare two numbers what we're really doing is performing a subtraction the difference between a and five is a third number we'll refer to as B there are only three possibilities for this number if B is negative it means a
a is lower than 5 if B is zero it means a and five are equal if B is positive it means a is greater than 5 so if we want to check if a is lower than five we can subtract these numbers whenever this condition is met the negative flag will turn on allowing us to use a jump negative instruction to detect it to implement this in our program we need to load the number five into another register and then subtract this value from the value of a which is already loaded in register zero immediately
after the subtraction we use a jump negative instruction to check if the result was negative and if so jump to the part of the code that instructs the CPU to execute the line inside the loop and after executing the line of code in the loop we need a jump instruction to return to the subtraction instruction we jump to the subtraction because before each iteration we need to check if the condition is still met if the subtraction doesn't trigger the negative flag the conditional jump won't occur and the CPU will execute the instruction immediately following it
remember the flag won't turn on when the Loop's condition is no longer met so at this point we can use an unconditional jump to break the loop since there's no more code after the loop the program should halt here if I were to match each line of this code snippet with its respective assembly code it would look something like this as long as the condition is met the conditional jump and the unconditional jump at location 9 will cause the CPU to execute the content of the loop but once the condition is no longer met the
conditional jump fails allowing the CPU to execute the next instruction an unconditional jump that sets the program counter out of the loop let's run the program you can see that while the value of the variable a is less than five these instructions are executed however since the value of the variable increases with each iteration at some point it will equal five causing the subtraction to no longer trigger the negative flag thereby breaking the loop now if you are wondering how if statements are processed by CPUs I have good news you already know how in the
while loop example we evaluate a condition if you think about it these two programs are very similar the only difference is that with the if statement we don't have to go back after executing the code inside the block so the unconditional jump is unnecessary if the condition is met the inner block will be executed if the condition is not met the conditional jump will fail and the CPU will execute the next instruction effectively skipping the code inside the if statement explained this way assembly is not that difficult is it also the comparison won't always be
the same we might want to use an equal 2 comparator which we can detect by checking if the subtraction triggers the zero flag then using the jump zero instruction or if we want to check if a is greater than 5 subtracting the two numbers shouldn't trigger neither the zero nor the negative Flags something we can detect using the jump above instruction before we wrap up here are a few clarifications the instructions I've been using don't come from any real architecture but from an instruction set I made up for this video I tried to use very
descriptive instruction names to make it easier for beginners to understand I I know dealing with assembly can be challenging but I've tried my best to make things intuitive and clear I hope you enjoyed this video If you learned something please hit that like button it's free and would really help me a lot also the tool I use to run these examples is available at this URL you can use it to run the program step by step as slowly or quickly as you want just keep in mind that is not responsive so try to use it
on a computer and not on a phone there are more software related videos on the way like CPU scheduling and threading so make sure to subscribe you don't want to miss them see you in the next one