General-purpose computer from scratch
The Nand to Tetris saga
Organization
The University of Chicago
Core Technologies
Python Hardware Simulator CPU Emulator VM Emulator Assembler Compiler
Domain
Computer Systems Architecture
Date
October 2023
Technical highlight
Each component in this big picture was built from scratch in a bottom up manner i.e starting from the hardware platform's logic gates designed in VHDL to the software platform's compiler.
Technical highlight
Functional Computer System Project
The first half of the course culminated in building a functional computer system by integrating key components developed earlier in the course:
Memory Components
RAM16K: Serves as the computer's short-term memory, where data and programs are temporarily stored while the system is running.
Screen and Keyboard: Facilitate user interaction by displaying output and receiving input.
CPU (Central Processing Unit) Components
A Register: A temporary storage area for data the CPU is currently processing, crucial for operations like calculations and data manipulation.
D Register: Holds the result of CPU operations, such as calculations or data fetched from memory, ensuring that results are available for subsequent steps.
ALU (Arithmetic Logic Unit): Performs arithmetic and logical operations, such as addition and comparison, required by the CPU.
Computer System
ROM32K: Stores the program code executed by the CPU, allowing the system to load and perform various tasks based on the given instructions.
By integrating these components, you gained a deeper understanding of how memory, CPU, and instruction storage work together to enable a computer to execute programs and interact with users.
Technical highlight
Assembler Development for Hack Hardware Platform
The project involved creating an assembler that translates programs written in Hack assembly language into binary code executable by the Hack hardware platform. The assembler handles two main types of instructions:
1. A-instructions
Function: Loads a specific value or memory address into a register.
2. C-instructions
Function: Defines computations, such as arithmetic operations or data transfer between registers and memory.
The project was completed in two stages:
1. Symbol-less Assembler
Objective: Create an assembler capable of directly converting A-instructions and C-instructions into binary code, without handling symbolic references.
Approach: Focused on translating instructions directly into the binary format that the Hack hardware understands.
2. Symbol Handling
Objective: Extend the assembler to handle symbolic references, such as memory addresses or variables.
Approach:
First Pass: The assembler scanned the entire program, building a symbol table to record the locations of labels and predefined variables.
Second Pass: The assembler replaced each symbolic reference with its corresponding binary address or value, ensuring the program could be executed correctly on the Hack hardware.
This approach enabled the assembler to handle both direct values and symbolic references, ensuring full functionality for programs targeting the Hack platform.
Technical highlight
Compiler Development Project
The project focused on developing a compiler to translate high-level code written in a procedural programming language into machine-readable instructions. The development was divided into two main phases:
1. Implementing a Procedural Programming Language
Variables: Managed the declaration and usage of variables within the code.
Expressions: Implemented the evaluation of mathematical and logical expressions.
Statements: Enabled the execution of various control structures, such as loops and conditionals.
2. Adding Object-Based Programming Features
Objects: Introduced the ability to define and manipulate objects, enabling more complex data structures.
Constructors: Implemented methods for initializing objects.
Methods: Enabled the definition and execution of functions tied to specific objects, expanding the language's capabilities.
Key Techniques Employed
Parsing: Handled the syntax analysis of the code, breaking it down into manageable components.
Symbol Tables: Used to track variable and function names, ensuring correct usage and scope management.
Compilation Engine: Coordinated the overall translation process from high-level code to machine code.
Code Generation: Produced final machine code, ensuring the translated code accurately represented the original source.
Takeaways