GammaCPU is a simple, 32-bit, stack-based CPU implemented in VHDL. It is designed to execute a subset of the WebAssembly (WASM) instruction set, focusing on 32-bit integer operations.
The project follows a modular design, separating the core CPU logic, the Arithmetic Logic Unit (ALU), and the data stack into distinct, testable components. A Python-based test runner is included to automate the simulation and verification process using GHDL.
The project is structured into several key files:
GammaCPU.vhdl
: The top-level CPU entity. It implements a state machine for the fetch-decode-execute cycle, orchestrating interactions between the ALU and the stack to process instructions.GammaALU.vhdl
: The Arithmetic Logic Unit. This component is responsible for all computational tasks, including arithmetic, comparison, bitwise, and shift/rotate operations.GammaStack.vhdl
: A 32-entry, 32-bit wide descending stack. It is used to store operands for the ALU and the results of computations.run.py
: A Python script that acts as a test runner. It automatically analyzes and elaborates the VHDL source files, runs all testbenches found in thetest/
directory, and reports a summary of the results.clean.py
: A utility script to remove simulation artifacts and log files (.vcd
,.cf
,.o
,.txt
, etc.).test/
: A directory containing testbenches for each module (cpu
,alu
,stack
) to ensure correctness.
- Stack-Based Machine: Instructions operate on values popped from the top of the stack, and the result is pushed back onto the stack. For example,
i32.add
pops two values, adds them, and pushes the sum. - State Machine: The
GammaCPU
is controlled by a multi-state state machine that implements the instruction pipeline:Fetch
,Decode
,Execute
,StackOperation
, and other intermediate states. The state machine handles operand fetching from the stack, enabling the ALU, and pushing results. - Instruction Format: The CPU decodes instructions based on the most significant byte (
instruction(31 downto 24)
). For immediate instructions likei32.const
, the value is embedded in the lower bytes of the instruction word.
The GammaCPU currently supports the following 32-bit integer instructions:
Opcode | Instruction | Description |
---|---|---|
0x41 |
i32.const |
Push a constant value onto the stack. |
Comparison | ||
0x45 |
i32.eqz |
Test if value is zero. |
0x46 |
i32.eq |
Test for equality. |
0x47 |
i32.ne |
Test for inequality. |
0x48 |
i32.lt_s |
Signed less than. |
0x49 |
i32.lt_u |
Unsigned less than. |
0x4A |
i32.gt_u |
Unsigned greater than. |
0x4B |
i32.gt_s |
Signed greater than. |
0x4C |
i32.le_s |
Signed less than or equal. |
0x4D |
i32.le_u |
Unsigned less than or equal. |
0x4E |
i32.ge_s |
Signed greater than or equal. |
0x4F |
i32.ge_u |
Unsigned greater than or equal. |
Arithmetic | ||
0x6A |
i32.add |
Addition. |
0x6B |
i32.sub |
Subtraction. |
0x6C |
i32.mul |
Multiplication. |
0x6D |
i32.div_s |
Signed division. |
0x6E |
i32.div_u |
Unsigned division. |
0x6F |
i32.rem_s |
Signed remainder. |
0x70 |
i32.rem_u |
Unsigned remainder. |
Bitwise & Shifts | ||
0x71 |
i32.and |
Bitwise AND. |
0x72 |
i32.or |
Bitwise OR. |
0x73 |
i32.xor |
Bitwise XOR. |
0x74 |
i32.shl |
Shift left. |
0x75 |
i32.shr_s |
Signed (arithmetic) shift right. |
0x76 |
i32.shr_u |
Unsigned (logical) shift right. |
0x77 |
i32.rotl |
Rotate left. |
0x78 |
i32.rotr |
Rotate right. |
- GHDL: A VHDL simulator. The scripts are written for GHDL. You can find installation instructions on the GHDL website.
- Python 3: To run the helper scripts (
run.py
,clean.py
).
To compile the VHDL code and run the entire test suite, execute the run.py
script:
python3 run.py
The script will:
- Analyze all
.vhdl
source files in the root directory. - Recursively search the
test/
directory for testbenches. - For each testbench found:
- Analyze, elaborate, and run the simulation.
- Generate a waveform file (
.vcd
) and a simulation log (simulation_output.txt
) in the test's directory. - Check the output for test failures.
- Print a summary of the results and exit with a status code
0
for success or1
for failure.
Example output:
🚀 Gamma Runner v1.0.0
|-✅ Analysis successful!
|-🧪 Running cpu tests...
|--✅ Analysis successful!
|--✅ Elaboration successful!
|--✅ Simulation successful!
|-🧪 Running alu tests...
|--✅ Analysis successful!
|--✅ Elaboration successful!
|--✅ Simulation successful!
|-🧪 Running stack tests...
|--✅ Analysis successful!
|--✅ Elaboration successful!
|--✅ Simulation successful!
To remove all generated files (logs, waveforms, object files, etc.), run the clean.py
script:
python3 clean.py
After running the tests, you can inspect the signal behavior using a VCD viewer like GTKWave. For example, to view the CPU test waveforms:
gtkwave test/cpu/changes.vcd
The project includes a comprehensive test suite located in the test/
directory, with separate subdirectories for each component (cpu
, alu
, stack
).
Testbenches use VHDL's assert
statement to verify behavior. A special string ___FAILOUT
is included in the report message of failing assertions. The run.py
script scans the simulation output for this string to programmatically determine if a test has failed, providing detailed error messages directly in the console.