I am very happy to share that I concluded the Computer Science Career Path on Codecademy!
Actually this happened already a little earlier this year, but only now the last piece has been finalized - a CPU Simulator. This was part of the Computer Architecture module.
What does the program do?
The goal of the project was to simulate some part of the inner workings of a CPU. I find this subject fascinating and since it is so broad I had to fight scope creep quite a bit. In the end I settled for simulating the CPU's fetch-decode-execute cycle by processing the following short list of simplified MIPS instructions:
CACHE,1
ADDI,R2,R2,2
ADD,R3,R2,R1
J,8
HALT,;
The CPU Simulator was built for demonstration purposes only and focuses on a very small portion of the CPU's and ALU's capabilities. It showcases the CPU's fetch-decode-execute cycle and processes the given commands. It will not be possible to give any other instructions to the CPU Simulator than the ones provided.
How did I code the CPU Simulator?
I implemented a class each for the Central Processing Unit (CPU) and the Arithmetic Logic Unit (ALU) in separate files. In yet another file I put the code for the simulation where everything comes together, the instructions are loaded in from a text file, CPU and ALU are imported, an instruction set architecture is defined and the simulation runs.
Within the CPU implementation I relied on deque from Python's collection module to create a queue for the instructions and the instructions' elements to be dequeued.
Whenever the instruction was of a category that was handled by the Control Unit of the CPU itself, the command would be executed within the logic of the CPU class. If, on the other hand, the instruction was such that it needed to be handled by the ALU, CPU passed it on to the ALU class and after processing received the result back, storing it where it needed to go according to the instruction as you can see in the following code snippet.
def pass_instruction_to_ALU_and_store_result(self, decoded_instruction):
print("\nPassing instruction to ALU...")
alu = ALU(decoded_instruction)
alu.execute_instruction()
result_of_operation = alu.result
decoded_instruction["val_dest_reg"] = result_of_operation
print(f"Receiving result from ALU and storing it in destination register {decoded_instruction['dest_reg']}")
self.registers[decoded_instruction["dest_reg"]] = result_of_operation
Below you can see two instructions from the list above being executed by the simulation.
Conclusion
The implementation of this project was elating and frustrating at the same time. While it definitely helped me gain a deeper understanding of how a CPU works as well as great appreciation of the levels of complexity involved it made me make the tough decision on which infinitesimally small portion of CPU logic I would have to focus on in order to keep the project scope feasible.
Please, feel free to download the program and let me know what you think. You can find it on GitHub.
s-mehnert / cpu_simulator
Run this script to see a demonstration of the fetch-decode-execute cycle using a set of pre-defined commands similar to MIPS instructions.
The simulation has been created using Python 3.11.5
To learn more about the topic, here is the site I found very useful to refer to while working on this project:
Top comments (0)