Skip to content

basmalaallam/Processor-Simulator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

8-Bit Pipelined Processor Simulator

A C-based simulator for a custom 8-bit Harvard-architecture processor with a 3-stage instruction pipeline. The simulator reads assembly programs, encodes them into 16-bit machine instructions, executes them cycle by cycle, and prints the full processor state after each clock cycle.

Overview

This project models the behavior of a small educational CPU designed for computer architecture coursework. It demonstrates how assembly instructions move through a pipelined processor, how registers and memory are updated, and how control-flow changes affect the pipeline.

The simulator includes an assembler-style parser, instruction encoder, register file, separate instruction and data memories, status flag updates, data hazard detection, branch/jump handling, and detailed execution traces.

Problem Statement

Modern processors improve throughput by overlapping instruction execution across pipeline stages. This simulator makes that behavior observable by implementing a simplified CPU that:

  • Loads assembly instructions from a text file.
  • Converts instructions into binary machine code.
  • Stores instructions and data in separate Harvard-architecture memories.
  • Executes instructions through Fetch, Decode, and Execute stages.
  • Detects read-after-write data hazards and inserts stalls.
  • Flushes incorrect pipeline stages after taken branches and jumps.
  • Prints registers, memory, status flags, program counter, and pipeline stages each cycle.

Features

  • 3-stage pipeline: Fetch, Decode, Execute
  • Harvard architecture with separate instruction and data memories
  • 1024-entry instruction memory with 16-bit encoded instructions
  • 2048-byte data memory
  • 64 general-purpose 8-bit registers
  • 16-bit program counter
  • 8-bit status register using the lower five flags: C, V, N, S, Z
  • Assembly parser with support for comments, whitespace normalization, commas, uppercase/lowercase input, decimal immediates, and hexadecimal immediates
  • R-type and I-type instruction encoding
  • Data hazard detection for register dependencies
  • Pipeline stalls for read-after-write hazards
  • Pipeline flushing for taken branches and jumps
  • Cycle-by-cycle execution trace
  • Final processor-state dump

Instruction Set

Instruction Type Description
ADD R1 R2 R-type Adds R2 to R1 and stores the result in R1.
SUB R1 R2 R-type Subtracts R2 from R1 and stores the result in R1.
MUL R1 R2 R-type Multiplies R1 by R2 and stores the low 8 bits in R1.
LDI R1 IMM I-type Loads a 6-bit signed immediate into R1.
BEQZ R1 IMM I-type Branches relative to the current instruction if R1 is zero.
AND R1 R2 R-type Performs bitwise AND and stores the result in R1.
OR R1 R2 R-type Performs bitwise OR and stores the result in R1.
JR R1 R2 R-type Jumps to the address formed by concatenating R1 and R2.
SAL R1 IMM I-type Shifts R1 left by the immediate value.
SAR R1 IMM I-type Performs arithmetic right shift on R1.
LB R1 ADDR I-type Loads a byte from data memory into R1.
SB R1 ADDR I-type Stores R1 into data memory.

System Architecture

Assembly File
     |
     v
Parser and Encoder
     |
     v
Instruction Memory (1024 x 16)
     |
     v
+---------+     +---------+     +----------+
| Fetch   | --> | Decode  | --> | Execute  |
+---------+     +---------+     +----------+
                                  |
                                  v
        Register File | SREG Flags | Data Memory | Program Counter

Core Design Decisions

  • uint16_t is used for instruction memory because each encoded instruction is 16 bits.
  • uint8_t is used for registers and data memory to match the simulated 8-bit processor width.
  • Each pipeline stage stores an Instruction struct containing decoded fields and the original source text, which makes tracing easier.
  • Branches and jumps are resolved in the Execute stage, then Fetch and Decode are flushed when control flow changes.
  • The simulator detects read-after-write hazards between Decode and Execute and inserts a one-cycle stall.

Technologies Used

  • C
  • Standard C library
  • Fixed-width integer types from stdint.h
  • Command-line file input
  • Assembly-style text parsing

Installation

Clone the repository:

git clone https://github.com/basmalaallam/Processor-Simulator.git
cd Processor-Simulator

Compile with GCC or Clang:

gcc src/main.c -o simulator

On Windows with Microsoft Visual C++:

cl src\main.c /Fe:simulator.exe

Usage

Run the included sample program:

./simulator examples/program.asm

On Windows PowerShell:

.\simulator.exe examples\program.asm

Run your own assembly file:

./simulator path/to/program.asm

If no file path is provided, the simulator looks for program.asm in the current working directory.

Example Program

LDI R1 5
LDI R2 10
ADD R1 R2
SB R1 20
LB R3 20
SUB R3 R1
BEQZ R3 1
LDI R4 99
LDI R4 7

Expected final highlights:

  • R1 = 15
  • R2 = 10
  • R3 = 0
  • R4 = 7
  • DataMemory[20] = 15

Project Structure

.
|-- README.md
|-- .gitignore
|-- examples/
|   `-- program.asm
`-- src/
    `-- main.c

Demo Video

Watch the project walkthrough and simulator demonstration here:

Processor Simulator Demo Video

Algorithms and Data Structures

  • Arrays model instruction memory, data memory, and the register file.
  • A structured Instruction record stores parsed operands, opcode, program counter, machine code, and source text.
  • A finite pipeline state is represented with three instruction-stage variables.
  • Bit masking and shifting are used for instruction encoding, flag updates, register concatenation, and immediate sign extension.
  • Read-after-write dependency detection determines when to stall the pipeline.
  • Control-flow instructions update the program counter and flush younger instructions.

Technical Challenges Solved

  • Encoding human-readable assembly into compact 16-bit machine instructions.
  • Simulating overlapping instruction execution with explicit pipeline state.
  • Preserving correct execution when dependencies exist between adjacent instructions.
  • Implementing branch and jump behavior without allowing wrong-path instructions to commit.
  • Updating status flags consistently across arithmetic, logical, and shift operations.
  • Producing a readable trace that helps debug processor behavior cycle by cycle.

Future Improvements

  • Add automated regression tests for parser, encoder, execution, hazards, and branch behavior.
  • Add a Makefile or CMake project for simpler cross-platform builds.
  • Split parser, CPU state, instruction execution, and printing into separate modules.
  • Add command-line flags for quiet mode, full memory printing, maximum cycles, and trace output files.
  • Add labels in assembly programs instead of requiring numeric branch offsets.
  • Add CI with compiler warnings enabled.
  • Add sample programs that demonstrate every instruction and edge case.

Key Learning Outcomes

  • Computer architecture fundamentals: pipelines, hazards, status flags, instruction formats, and Harvard memory organization.
  • Low-level C programming with fixed-width integer types and bitwise operations.
  • Designing debuggable simulations with clear state transitions.
  • Translating assembly-like input into executable machine-level behavior.
  • Explaining technical systems in a way that is readable to both engineers and reviewers.

About

C simulator for an 8-bit pipelined Harvard-architecture processor with assembly parsing, instruction encoding, hazard detection, and cycle-by-cycle execution tracing.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages