EECS 370 - Computer Organization
This class covered the fundamentals of how computers work, from assembly code to memory management to what's actually happening on the hardware level that allows computation to take place.
Programming In Assembly
One of the first skills learned in this class was how to program with assembly. Working with a simple assembly language for an invented computer called the LC2K, and later with ARM x86, we wrote various programs. These were meant to accomplish anything from simple multiplication - there was no command implementing this in the custom language - to a function which would recursively calculate nCr through the property nCr = (n-1) C r + (n-1) C (r-1). We additionally worked to optimize the behavior of these functions, as we had to reduce the number of cycles executed under some limit introduced by the spec.
Building an Assembler
In addition to this, we built an assembler, which would take the assembly code for LC2K and render it as the corresponding binary. As the class progressed, we periodically updated our assembler to reflect new knowledge, such that it eventually had functionalities including assembling object files and maintaining symbol tables such that multiple files of assembly code could later be combined with a linker.
Building a Hardware Simulator
Our compiled binary would be useless without something to execute it. We initially implemented a single cycle processer that could execute our code one instruction at a time, but as the class progressed we correspondingly advanced our design. Our final iteration involved implementing a multi cycle processor with data forwarding and hazard mitigation. We also introduced a simulated cache, such that a its specifications (block size, set size, and number of sets) could be determined by the user at runtime. This allowed us to model where data was coming from when it was requested by the processer, helping us identify bottlenecks in our code to speed up execution.
Single and Multi-Cycle Processer Design
In addition to implementing a processer whose design was covered in lecture, we were often asked to create our own processor design. Using a limited budget for components like ALUs and MUXs, we were asked to implement hardware paths that would allow execution of new and unfamiliar opcodes. After implementing this hardware, we would be asked to design a corresponding control ROM, and evaluate the efficiency and speed of our overall design.