A Simple Program on a Low Level - Mini Tutorial
I'm not too big of a fan of introductions as I feel it takes away from the content of the tutorial and is more so just padding to make it longer. So going with this theme, I'll just explicitly list the objective of this tutorial down below:
To explain how a computer runs a simple program on a very low level (lower than assembly).
This may seem lame at first but trust me, there is a surprising amount of complexity, just to run a simple program which I hope to explore to the fullest extent.
The Computer (specifications)
Now that we have moved past the boring part, let's get into explaining the computer on which we will be running this program. One of the major issues with trying to use a modern computer is just the sheer complexity and size, something that is very hard for a beginner to wrap their head around. Keeping that in mind, I have devised a simple hypothetical computer, which I'll refer to as YAX (thought it would sound cool, but no actual purpose behind the name) for the rest of the tutorial.
YAX is a basic computer consisting of 4 special registers, 4-bit memory addresses, and a total of 4 opcodes. This could be a lot to unpack for many of you so let me take some time to walk through this step by step.
First up we have the 4 special registers. These are essentially 1 byte (8 bits) wide and are used for temporarily storing data throughout the program. For this tutorial, let's call them registers A, B, C, and D.
Second, we have the 4-bit memory addresses. For those of you not familiar with binary, 4 bit means that we can have only 4 bits in each address, making 1111 (15) the biggest unsigned binary number that we can use. Based on this we will have a total of 15 memory addresses, each containing 1 byte of data.
Lastly, we have the opcodes which for now will be limited to four simple instructions. These four have been listed down below in a table:
|0001||LOAD_A $7||Loads the memory address 7 into register A|
|0010||LOAD_B $8||Loads the memory address 8 into register B|
|0011||ADD_A #B||Adds the contents of register B into register A|
|0100||STORE_A $9||Stores the value of register A into memory address 9|
Technically speaking, the memory addresses and the registers would be accepted as changeable arguments, but once again for the simplicity of the tutorial I have chosen to stick with just plain arguments.
The Computer Again (graphical)
Hopefully, by now you have read the last section of the tutorial in which I attempted to explain YAX, more so from a technical standpoint than a graphical one. I get how difficult this could be for someone to wrap their head around so considering that I have decided to also create a diagram of YAX below:
So to walk you through the diagram, you can see the 4 special registers labeled at the top all connected to a data wire stemming from the RAM. Now underneath the registers, there is an ALU that essentially does all the math and logic on the computer. I don't want to go too deep into the ALU but for the sake of this tutorial, let's just say it will be doing the math. Next to we have the control unit which is like the brain of a computer. The control unit is in charge of running the programs and interacting with the RAM which is outside of the CPU. Personally, I like to think of it as a hub for all the information to be processed through and sent to its destination.
I could go on a lot further with this but I'm trying to keep it as a mini-tutorial so I better move on to the program itself.
The program as the name suggests is what we will be running on YAX. Long story short the program will pretty much be adding 2 numbers together and storing them in a memory address. It would look something like this:
As far as the symbols in the code above go, any number after a
$ signifies a memory address while anything after a
# shows a register.
Taking that into consideration we can tell that the first line of code loads the contents of memory address 7 into register A. The second line of code does the same thing except with register B and a different memory address.
The third line of code which is
ADD_A #B is a bit more complex but is in essence adding the contents of register B into A thus changing the value of register A but not B.
The final line is hopefully pretty self-explanatory but all it does is store whatever is in register A into the memory.
I also feel like it's pretty important to give you a look at the memory before we run the program so here it is:
Moving on let's get to running the program.
Running the Program
I think that the actual running of the program would be simplest to do in bullet form, so I think I'll go with that.
- The control unit reads from address 1 and determines the opcode.
- The control unit then enables the read wire on the RAM and uses the multiplexer to select the contents of address 7.
- These contents rea passed along the data wire until it reaches and is stored in register A.
- The control unit reads from address 3 and determines the opcode.
- The control unit then enables the read wire on the RAM and uses the multiplexer to select the contents of address 8.
- These contents rea passed along the data wire until it reaches and is stored in register B.
And yes the second line is just the first one copied and pasted.
- The control unit reads from address 3 and determines the opcode.
- The control unit then passed the values stores in registers A and B into the 2 inputs of the ALU.
- The control unit then sets the operation on the ALU to add which will require no extra processing.
- The ALU will then proceeds to add the 2 values together before being instructed to pass the sum into register A.
- The control unit reads from address 4 and determines the opcode.
- The control unit then enables the write wire on the RAM and uses the multiplexer to select the contents of address 9.
- The contents of register A are then passed along the data wire and into address 9, therefore, achieving our sum of 8.
That's all for today and I hope you enjoyed this mini tutorial and maybe even learned something new about computers from it. Please comment with any sort of feedback/comments and questions are always appreciated.
@IMayNotBeMe so most ALUs can do a few basic logic operations such as AND, OR, and XOR but won’t be able to do anything like multiplication. Stuff like multiplication and division is left to the user to write programs for simply because it’s too complicated for a single circuit. Modern ALUs also do some bit operations but most of those aren’t too important. I will be getting around to writing a tutorial on how a ALU works but just as a question, would you be looking for the specific logic gates or something more conceptual?