• Stars
    star
    145
  • Rank 253,358 (Top 6 %)
  • Language
    C++
  • License
    Other
  • Created over 4 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Implementing a CPU emulator using C++Templates

Template-CPU

Implementing a CPU emulator using C++ Meta Programming with Concepts. The emulator can execute arbitrary programs written in Template-assembly (which is the C++ type system), under the limitations of the compiler. This proves the turing-completeness of the C++-Type-System.

Build Instructions

Compiler

You need a C++-Compiler with support for Concepts (i.e. C++-20), for example:

  • GCC >= 9
  • Clang >= 10

Building

The project is a cmake project, for building execute (in the root directory of the repo):

mkdir build
cd build
cmake ..
make

now there is an executable TemplateCpu.

Syntax

The syntax is pure C++, with classes which behave like instructions, see the examples below for more information on Template-Assembly.

Instructions

Below are all supported instructions, for most instructions there is also an Immediate version, denoted by an "I" at the end (so Add-Immediate is AddI), which takes a constant literal instead of a register as (last) argument. The full declaration of all Instruction with a more detailed explanation can be found in instruction_def.hpp.

Name Description Arguments C++-Equivalent
Add Add res,a,b res = a+b
Sub Subtract res,a,b res = a-b
Mul Multiply res,a,b res = a*b
Div Divide (Exception at divide by zero) res,a,b res = a/b
And Bitwise And res,a,b res = a & b
Or Bitwise Or res,a,b res = a | b
XOr Bitwise Exclusive-Or res,a,b res = a ^ b
Less Smaller comparison res,a,b res = a < b
Greater Greater comparison res,a,b res = a > b
Jump Jump to address in program reg goto reg
BranchEq Branch/Jump if equal a,b,reg if (a == b) {goto reg;}
BranchNEq Branch/Jump if not equal a,b.reg if (a != b) {goto reg;}
Store Store register to memory addr_reg,reg *addr_reg = reg
Load Load from memory into register reg,addr_reg reg = *addr_reg

Examples

As an example there are two versions of a program to calculate the n-th fibonacci number additionally the last example is the implementation of a turing machine using Template-assembly.

Running a program

There are some utility functions to help debugging the Template-assembly code. A basic framework which shows some debug information looks like this:

#include "cpu.hpp"
#include "util.hpp"

using my_program = 
        DeclareProgram<
            INSTRUCTIONS_HERE      
        >;


int main() {
    using result = Cpu<my_program>::run;
    using printer = printer<result::reg, result::mem>;

    if constexpr (result::is_breakpoint) {
        std::cout << "Stopped at breakpoint (pc=" << result::pc << ")" << std::endl;
    }

    std::cout << "Executed " << result::instr_count << " instructions\n" << std::endl;
    std::cout << "Registers:" << std::endl;
    printer::reg();

    std::cout << "\nMemory:" << std::endl;
    printer::mem();

    return 0;
}

Fibonacci-Iterative

The iterative solution calculates the fibonacci number using a loop. In (normal run-time) C++ the code would look like this:

int fib(int a) {
    int b = 1;
    int c = 0;
    int d = 0;
    int e = 1;
    
    do {
        ++b;
        c = d;
        d = e;
        e = c + d;
    } while (a != b);
}

fib(40);

In Template-Assembly the code looks like this:

using fib_iterative =
        DeclareProgram<
            AddI<int, Register::A, Register::ZERO, 40>,// 0: a = 40
            AddI<int, Register::B, Register::ZERO, 1>, // 1: b = 1
            AddI<int, Register::C, Register::ZERO, 0>, // 2: c = 0
            AddI<int, Register::D, Register::ZERO, 0>, // 3: d = 0
            AddI<int, Register::E, Register::ZERO, 1>, // 4: e = 1
            AddI<int, Register::B, Register::B, 1>,    // 5: b += 1
            Mov<Register::C, Register::D>,             // 6: c = d
            Mov<Register::D, Register::E>,             // 7: d = e
            Add<Register::E, Register::C, Register::D>,// 8: e = c + d
            BranchNEqI<int, Register::A, Register::B, 5>, // 9: if a != b -> jmp 5
            StoreI<0, Register::E>
        >;

Fibonacci-Recursive

The recursive implementations demonstrates function calls and the stack. In (normal run-time) C++ the code would look like this:

int fib(int a) {
    if (a > 2) {
        return fib(a-1) + fib(a-2);
    } else {
        return 1;
    } 
}
fib(8);

In template assembly the code looks like this:

/*
 * Stack Layout
 * STACK_PTR, RET, ARG, RES1 = FIB(ARG-1), ...
 */
using fib_recursive =
        DeclareProgram<
            // Init
            AddI<int, Register::A, Register::ZERO, 8>,              //0: set max value
            AddI<int, Register::RET, Register::ZERO, 31>,           //1: store last address in RET

            // Check if base
            GreaterI<int, Register::B, Register::A, 2>,             //2: LABEL_0 b = (a > 2)
            BranchNEqI<int, Register::ZERO, Register::B, 5>,        //3: if a > 2 -> jmp LABEL_1
            BranchEqI<int, Register::ZERO, Register::B, 29>,        //4: else -> jmp LABEL_2

            // Build up stack
            Store<Register::STACK_PTR, Register::STACK_PTR>,        //5: LABEL_1 (recursion) push STACK_PTR to stack
            AddI<int, Register::STACK_PTR, Register::STACK_PTR, 1>, //6: Forward stackptr to stack
            Store<Register::STACK_PTR, Register::RET>,              //7: store ret on stack
            AddI<int, Register::STACK_PTR, Register::STACK_PTR, 1>, //8: Forward stackptr to stack
            Store<Register::STACK_PTR, Register::A>,                //9: push a to stack
            AddI<int, Register::STACK_PTR, Register::STACK_PTR, 2>, //10: Forward stackptr to stack by 2

            // Recursion
            AddI<int, Register::A, Register::A, -1>,                //11: a -= 1
            AddI<int, Register::RET, Register::ZERO, 14>,           //12: Store return address
            JumpI<int, 2>,                                          //13: Recursion, jump to LABEL_0, result in e
            AddI<int, Register::B, Register::STACK_PTR, -1>,        //14: b point to RES1
            Store<Register::B, Register::E>,                        //15: Save e to RES1
            AddI<int, Register::B, Register::STACK_PTR, -2>,        //16: b points to ARG on stack
            Load<Register::A, Register::B>,                         //17: load ARG from stack into a
            AddI<int, Register::A, Register::A, -2>,                //18: a -= 2
            AddI<int, Register::RET, Register::ZERO, 21>,           //19: Store return address
            JumpI<int, 2>,                                          //20, recursion, jump to LABEL_0, result in e

            // Final result
            AddI<int, Register::B, Register::STACK_PTR, -1>,        //21: b points to RES1
            Load<Register::C, Register::B>,                         //22: load RES1 into C
            Add<Register::E, Register::E, Register::C>,             //23: e = e + c = fib(a-1) + fib(a-2)

            // Cleanup stack
            AddI<int, Register::B, Register::STACK_PTR, -3>,        //24: b points to RET
            Load<Register::RET, Register::B>,                       //25: Restore RET
            AddI<int, Register::B, Register::STACK_PTR, -4>,        //26: b points to STACK_PTR
            Load<Register::STACK_PTR, Register::B>,                 //27: Restore RET
            JumpI<int, 30>,                                         //28: jmp LABEL_3

            // Base
            AddI<int, Register::E, Register::ZERO, 1>,              //29: LABEL_2: e = 1

            // Return
            Jump<Register::RET>                                     //30: LABEL_3, return
        >;

Turing Machine

There is also an emulator of a turing machine built upon the CPU emulator. The complete code can be found in examples/turing_machine.hpp there is also a python implementation of the same code located in examples/turing_machine.py this code is more readable, but is consistent to the template assembly implementation. Furthermore the python implementation allows the user to directly specify transitions without calculating memory addresses manually. The memory used for the python example can also be used to directly create the correct initialization code for the template assembly implementation.

More Repositories

1

CubeMxCMake

Generate a CMakeLists.txt from an STM32-CubeMx Project
Python
16
star
2

FastObjectDetectionInDensePointClouds

Bachelorthesis: "Fast Object Detection in Dense Point Clouds" at Institute of Measurement, Control and Microtechnology at Ulm University
TeX
6
star
3

pic32ubl-qt

Port of the PIC32-Bootloader-Application for Linux and MacOs.
C++
5
star
4

RoboCup-Simulation

A RoboCup Junior Soccer Simulation based on Electron
JavaScript
4
star
5

BikeSimulation

Python
3
star
6

HexToDecToBinToAsciiToAnything

Small online converter for different representations of values (Dec, Bin, Hex, Oct, ASCII) with integrated ALU like tool (+, -, *, /, AND, OR, XOR...)
JavaScript
3
star
7

EkfSlam

C++
2
star
8

WuppDiKlickDi

Generating Techno using Convolutional Autoencoders
Python
2
star
9

IOSet

Using the C++ type system to define a set of valid input values for a function and automatically deduce all possible output values
C++
2
star
10

LightControlFirmwareIR

Controlling the Led-Strip in my room via IR
C
1
star
11

HuffmannEncoder

Implementation of a Huffmann Encoder in C++
C++
1
star
12

Dungeon

Based on a project done in school but now in 3D with JS
JavaScript
1
star
13

SerialToolbox

A serial port terminal and debugger, inspired by HTerm
C++
1
star
14

LoRaReceiver

1
star
15

hmZusammenfassung

Zusammenfassung des Skripts der Vorlesung "Höhere Mathematik für Physiker und Ingenieure" der Uni Ulm.
TeX
1
star
16

SicherheitInItSystemen

Lösungen zur Übung für "Sicherheit in It-Systemen" an der Uni Ulm
Shell
1
star
17

GitIntro

Eine Einführung in das VCS Git
TeX
1
star
18

Sym

Framework for efficient symbolic calculations during compile time using C++ zero cost abstractions.
C++
1
star
19

Schulplanner3

A webapp for managing your schoolday
HTML
1
star
20

NeuralNetworkQuantizationPerformanceBenchmark

Comparing the inference performance of neural networks with and without quantization
C++
1
star
21

ARDF-Firmware

Firmware for an ARDF-Sender using an Attiny 44
C
1
star
22

RoboCupCode

Main software for our soccer robots (open league) for RoboCup-Junior. With this code we won the RoboCup 2016.
C++
1
star
23

PlotStuff

I was annoyed of Matlab...
C++
1
star
24

GdRa

Lösungen zu den Übungsblättern der Vorlesung "Grundlagen der Rechnerarchitektur" an der Universität Ulm.
TeX
1
star
25

Zusammenfassung-Filter-und-Trackingverfahren

Zusammenfassung zum Modul Filter- und Trackingverfahren an der Universität Ulm
TeX
1
star
26

HighPerformanceComputing1

Solutions for the Lab Sessions for the module "High Performance Computing 1" at Ulm University
C++
1
star
27

AdventOfCode2020

Advent of Code 2020, languages according to the TIOBE index
C++
1
star
28

LightControlAndroid

Controlling all the lights in my room
Java
1
star
29

eduJS

A simple HTML editor with a JS editor for creating simple webapps using HTML5 and Javascript. Mainly for educational purpose.
HTML
1
star
30

TensorflowInferenceBenchmark

Comparing the inference speed of different implementations of Tensorflow in C++
C++
1
star
31

TemplateCpuReport

Report for the Lecture "Objektorientierte Programmierung mit C++" (OOP with C++), at Ulm University
TeX
1
star
32

EidI-Uni-Ulm

Lösungen für Übungsblätter der Vorlesung "Einführung in die Informatik"
HTML
1
star