diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..473e0e348315eb4b4cc98afc4e9a60832546e0e6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,30 @@
+.vs/
+.vscode/
+build*/
+bin*/
+logs/
+dist/
+CMakeLists.txt.user*
+*.autosave
+*.creator
+*.creator.user*
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+*~
+.fuse_hudden*
+.directory
+.Trash-*
+.nfs*
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+$RECYCLE.BIN/
+*.stackdump
+[Dd]esktop.ini
+*.egg-info
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index 2130f26d6be5ccf8185aebd9f03003645cb9c2f8..0000000000000000000000000000000000000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-stages:
-  - build
-
-PythonBuild:
-  stage: build
-  artifacts:
-    untracked: true
-  script:
-    - apt-get update && apt-get install python3 -y
-    - python3 helloworld.py
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7f6908ed2d0a352aed1e16f936a8a1d5593cccd4
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,77 @@
+cmake_minimum_required(VERSION 3.8)
+
+project(
+	"B-ASIC"
+	VERSION 0.0.1
+	DESCRIPTION "Better ASIC Toolbox for python3"
+	LANGUAGES C CXX
+)
+
+find_package(fmt 6.1.2 REQUIRED)
+find_package(pybind11 CONFIG REQUIRED)
+
+set(LIBRARY_NAME "b_asic")
+set(TARGET_NAME "_${LIBRARY_NAME}")
+if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+	include(GNUInstallDirs)
+	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_INSTALL_LIBDIR}")
+endif()
+
+add_library(
+	"${TARGET_NAME}" MODULE
+	"${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp"
+)
+add_library(
+	"${TARGET_NAME}:${TARGET_NAME}"
+	ALIAS "${TARGET_NAME}"
+)
+
+set_target_properties(
+	"${TARGET_NAME}"
+	PROPERTIES
+		PREFIX ""
+)
+
+target_include_directories(
+	"${TARGET_NAME}"
+    PRIVATE
+        "${CMAKE_CURRENT_SOURCE_DIR}/src"
+)
+
+target_compile_features(
+	"${TARGET_NAME}"
+	PRIVATE
+		cxx_std_17
+)
+target_compile_options(
+	"${TARGET_NAME}"
+	PRIVATE
+		$<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:
+			-W -Wall -Wextra -Werror -Wno-psabi -fvisibility=hidden
+			$<$<CONFIG:Debug>:-g>
+			$<$<NOT:$<CONFIG:Debug>>:-O3>
+		>
+		$<$<CXX_COMPILER_ID:MSVC>:
+			/W3 /WX /permissive- /utf-8
+			$<$<CONFIG:Debug>:/Od>
+			$<$<NOT:$<CONFIG:Debug>>:/Ot>
+		>
+)
+
+target_link_libraries(
+	"${TARGET_NAME}"
+	PRIVATE
+		fmt::fmt-header-only
+		pybind11::module
+)
+
+add_custom_target(
+	copy_python_files ALL
+	COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_LIST_DIR}/${LIBRARY_NAME}" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIBRARY_NAME}"
+	COMMENT "Copying python files to ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIBRARY_NAME}"
+)
+add_custom_target(
+	copy_misc_files ALL
+	COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_LIST_DIR}/README.md" "${CMAKE_CURRENT_LIST_DIR}/LICENSE" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
+	COMMENT "Copying misc. files to ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
+)
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..ce996f6c4ffcc6a70d095c24ed296ec3b69e5f43
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,4 @@
+include README.md
+include LICENSE
+include CMakeLists.txt
+recursive-include src *.cpp *.h
diff --git a/README.md b/README.md
index f126999b47d9a015add1400c4ec887e1c8e0a9e7..4917b55e937ac4e1a158f78ecce77e63d7e60cac 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,91 @@
-<img src="https://files.slack.com/files-pri/TSHPRJY83-FTTRW9MQ8/b-asic-logo-opaque.png"  width="318" height="100">
-<br>
-<h3>The leading company in circuit design<h3>
\ No newline at end of file
+<img src="logo.png" width="278" height="100">
+
+# B-ASIC - Better ASIC Toolbox
+B-ASIC is an ASIC toolbox for Python 3 that simplifies circuit design and optimization.
+
+## Prerequisites
+The following packages are required in order to build the library:
+* cmake 3.8+
+  * gcc 7+/clang 7+/msvc 16+
+  * fmtlib 6.1.2+
+  * pybind11 2.3.0+
+* python 3.6+
+  * setuptools
+  * wheel
+  * pybind11
+
+## Development
+How to build and debug the library during development.
+
+### Using CMake directly
+How to build using CMake.
+
+#### Configuring
+In `B-ASIC`:
+```
+mkdir build
+cd build
+cmake ..
+```
+
+#### Building (Debug)
+In `B-ASIC/build`:
+```
+cmake --build .
+```
+The output gets written to `B-ASIC/build/lib`.
+
+#### Building (Release)
+In `B-ASIC/build`:
+```
+cmake --build . --config Release
+```
+The output gets written to `B-ASIC/build/lib`.
+
+### Using setuptools to create a package
+How to create a package using setuptools.
+
+#### Setup (Binary distribution)
+In `B-ASIC`:
+```
+python3 setup.py bdist_wheel
+```
+The output gets written to `B-ASIC/dist`.
+
+#### Setup (Source distribution)
+In `B-ASIC`:
+```
+python3 setup.py sdist
+```
+The output gets written to `B-ASIC/dist`.
+
+#### Installation (Binary distribution)
+In `B-ASIC`:
+```
+python3 -m pip install b_asic-<version>-<cpver>-<cpver>_<arch>.whl
+```
+
+#### Installation (Source distribution)
+In `B-ASIC`:
+```
+python3 -m pip install b-asic-<version>.tar.gz
+```
+
+## Usage
+How to build and use the library as a user.
+
+### Installation
+```
+python3 -m pip install b_asic
+```
+
+### Importing
+```
+python3
+>>> import b_asic as asic
+>>> help(asic)
+```
+
+## License
+B-ASIC is distributed under the MIT license.
+See the included LICENSE file for more information.
\ No newline at end of file
diff --git a/b_asic/__init__.py b/b_asic/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8bbc17ab50204e26db7dcaf0569cbfe316b3dc3a
--- /dev/null
+++ b/b_asic/__init__.py
@@ -0,0 +1,13 @@
+"""
+Better ASIC Toolbox.
+TODO: More info.
+"""
+from _b_asic import *
+from b_asic.operation import *
+from b_asic.ops import *
+from b_asic.pc import *
+from b_asic.port import *
+from b_asic.schema import *
+from b_asic.sfg import *
+from b_asic.signal import *
+from b_asic.simulation import *
\ No newline at end of file
diff --git a/b_asic/operation.py b/b_asic/operation.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bea5047775df99993f9bf2dedfdd1fb4209834b
--- /dev/null
+++ b/b_asic/operation.py
@@ -0,0 +1,210 @@
+"""
+B-ASIC Operation Module.
+TODO: More info.
+"""
+from b_asic.port import InputPort, OutputPort
+from b_asic.signal import SignalSource, SignalDestination
+from b_asic.simulation import SimulationState, OperationState
+from abc import ABC, abstractmethod
+from numbers import Number
+from typing import NewType, List, Dict, Optional, final
+
+OperationId = NewType("OperationId", int)
+
+class Operation(ABC):
+	"""
+	Operation interface.
+	TODO: More info.
+	"""
+
+	@abstractmethod
+	def identifier(self) -> OperationId:
+		"""
+		Get the unique identifier.
+		"""
+		pass
+
+	@abstractmethod
+	def inputs(self) -> List[InputPort]:
+		"""
+		Get a list of all input ports.
+		"""
+		pass
+
+	@abstractmethod
+	def outputs(self) -> List[OutputPort]:
+		"""
+		Get a list of all output ports.
+		"""
+		pass
+
+	@abstractmethod
+	def input_count(self) -> int:
+		"""
+		Get the number of input ports.
+		"""
+		pass
+
+	@abstractmethod
+	def output_count(self) -> int:
+		"""
+		Get the number of output ports.
+		"""
+		pass
+
+	@abstractmethod
+	def input(self, i: int) -> InputPort:
+		"""
+		Get the input port at index i.
+		"""
+		pass
+
+	@abstractmethod
+	def output(self, i: int) -> OutputPort:
+		"""
+		Get the output port at index i.
+		"""
+		pass
+
+	@abstractmethod
+	def params(self) -> Dict[str, Optional[Any]]:
+		"""
+		Get a dictionary of all parameter values.
+		"""
+		pass
+
+	@abstractmethod
+	def param(self, name: str) -> Optional[Any]:
+		"""
+		Get the value of a parameter.
+		Returns None if the parameter is not defined.
+		"""
+		pass
+
+	@abstractmethod
+	def set_param(self, name: str, value: Any) -> None:
+		"""
+		Set the value of a parameter.
+		The parameter must be defined.
+		"""
+		pass
+
+	@abstractmethod
+	def evaluate_outputs(self, state: SimulationState) -> List[Number]:
+		"""
+		Simulate the circuit until its iteration count matches that of the simulation state,
+		then return the resulting output vector.
+		"""
+		pass
+
+	@abstractmethod
+	def split(self) -> List[Operation]:
+		"""
+		Split the operation into multiple operations.
+		If splitting is not possible, this may return a list containing only the operation itself.
+		"""
+		pass
+	
+	# TODO: More stuff.
+
+class BasicOperation(ABC, Operation):
+	"""
+	Generic abstract operation class which most implementations will derive from.
+	TODO: More info.
+	"""
+
+	_identifier: OperationId
+	_input_ports: List[InputPort]
+	_output_ports: List[OutputPort]
+	_parameters: Dict[str, Optional[Any]]
+
+	def __init__(self, identifier: OperationId):
+		"""
+		Construct a BasicOperation.
+		"""
+		self._identifier = identifier
+		self._input_ports = []
+		self._output_ports = []
+		self._parameters = {}
+
+	@abstractmethod
+	def evaluate(self, inputs: list) -> list:
+		"""
+		Evaluate the operation and generate a list of output values given a list of input values.
+		"""
+		pass
+
+	@final
+	def id(self) -> OperationId:
+		return self._identifier
+		
+	@final
+	def inputs(self) -> List[InputPort]:
+		return self._input_ports.copy()
+
+	@final
+	def outputs(self) -> List[OutputPort]:
+		return self._output_ports.copy()
+
+	@final
+	def input_count(self) -> int:
+		return len(self._input_ports)
+
+	@final
+	def output_count(self) -> int:
+		return len(self._output_ports)
+
+	@final
+	def input(self, i: int) -> InputPort:
+		return self._input_ports[i]
+
+	@final
+	def output(self, i: int) -> OutputPort:
+		return self._output_ports[i]
+
+	@final
+	def params(self) -> Dict[str, Optional[Any]]:
+		return self._parameters.copy()
+	
+	@final
+	def param(self, name: str) -> Optional[Any]:
+		return self._parameters.get(name)
+
+	@final
+	def set_param(self, name: str, value: Any) -> None:
+		assert name in self._parameters # TODO: Error message.
+		self._parameters[name] = value
+
+	def evaluate_outputs(self, state: SimulationState) -> List[Number]:
+		# TODO: Check implementation.
+		input_count: int = self.input_count()
+		output_count: int = self.output_count()
+		assert input_count == len(self._input_ports) # TODO: Error message.
+		assert output_count == len(self._output_ports) # TODO: Error message.
+
+		self_state: OperationState = state.operation_states[self.identifier()]
+
+		while self_state.iteration < state.iteration:
+			input_values: List[Number] = [0] * input_count
+			for i in range(input_count):
+				source: SignalSource = self._input_ports[i].signal().source
+				input_values[i] = source.operation.evaluate_outputs(state)[source.port_index]
+
+			self_state.output_values = self.evaluate(input_values)
+			assert len(self_state.output_values) == output_count # TODO: Error message.
+			self_state.iteration += 1
+			for i in range(output_count):
+				for signal in self._output_ports[i].signals():
+					destination: SignalDestination = signal.destination
+					destination.evaluate_outputs(state)
+
+		return self_state.output_values
+
+	def split(self) -> List[Operation]:
+		# TODO: Check implementation.
+		results = self.evaluate(self._input_ports)
+		if all(isinstance(e, Operation) for e in results):
+			return results
+		return [self]
+		
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/b_asic/ops.py b/b_asic/ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b3707254e8faceed0727da1ff93b9ad2582c35a
--- /dev/null
+++ b/b_asic/ops.py
@@ -0,0 +1,75 @@
+"""
+B-ASIC Core Operations Module.
+TODO: More info.
+"""
+
+from b_asic.operation import OperationId, Operation, BasicOperation
+from numbers import Number
+from typing import final
+
+class Input(Operation):
+	"""
+	Input operation.
+	TODO: More info.
+	"""
+
+	# TODO: Implement.
+	pass
+
+class Constant(BasicOperation):
+	"""
+	Constant value operation.
+	TODO: More info.
+	"""
+
+	def __init__(self, identifier: OperationId, value: Number):
+		"""
+		Construct a Constant.
+		"""
+		super().__init__(identifier)
+		self._output_ports = [OutputPort()] # TODO: Generate appropriate ID for ports.
+		self._parameters["value"] = value
+
+	@final
+	def evaluate(self, inputs: list) -> list:
+		return [self.param("value")]
+
+class Addition(BasicOperation):
+	"""
+	Binary addition operation.
+	TODO: More info.
+	"""
+
+	def __init__(self, identifier: OperationId):
+		"""
+		Construct an Addition.
+		"""
+		super().__init__(identifier)
+		self._input_ports = [InputPort(), InputPort()] # TODO: Generate appropriate ID for ports.
+		self._output_ports = [OutputPort()] # TODO: Generate appropriate ID for ports.
+
+	@final
+	def evaluate(self, inputs: list) -> list:
+		return [inputs[0] + inputs[1]]
+
+
+class ConstantMultiplication(BasicOperation):
+	"""
+	Unary constant multiplication operation.
+	TODO: More info.
+	"""
+
+	def __init__(self, identifier: OperationId, coefficient: Number):
+		"""
+		Construct a ConstantMultiplication.
+		"""
+		super().__init__(identifier)
+		self._input_ports = [InputPort()] # TODO: Generate appropriate ID for ports.
+		self._output_ports = [OutputPort()] # TODO: Generate appropriate ID for ports.
+		self._parameters["coefficient"] = coefficient
+
+	@final
+	def evaluate(self, inputs: list) -> list:
+		return [inputs[0] * self.param("coefficient")]
+
+# TODO: More operations.
\ No newline at end of file
diff --git a/b_asic/pc.py b/b_asic/pc.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc18d6af1dea2843257d53f9b3008d1decde3604
--- /dev/null
+++ b/b_asic/pc.py
@@ -0,0 +1,24 @@
+"""
+B-ASIC Precedence Chart Module.
+TODO: More info.
+"""
+
+from b_asic.sfg import SFG
+
+class PrecedenceChart:
+	"""
+	Precedence chart constructed from a signal flow graph.
+	TODO: More info.
+	"""
+
+	sfg: SFG
+	# TODO: More members.
+
+	def __init__(self, sfg: SFG):
+		"""
+		Construct a PrecedenceChart.
+		"""
+		self.sfg = sfg
+		# TODO: Implement.
+
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/b_asic/port.py b/b_asic/port.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b1e8d2025ee5696f1365b8b8b2195167620925f
--- /dev/null
+++ b/b_asic/port.py
@@ -0,0 +1,147 @@
+"""
+B-ASIC Port Module.
+TODO: More info.
+"""
+
+from b_asic.signal import Signal
+from abc import ABC, abstractmethod
+from typing import NewType, Optional, List, Dict, final
+
+PortId = NewType("PortId", int)
+
+class Port(ABC):
+	"""
+	Abstract port class.
+	TODO: More info.
+	"""
+
+	_identifier: PortId
+
+	def __init__(self, identifier: PortId):
+		"""
+		Construct a Port.
+		"""
+		self._identifier = identifier
+	
+	@final
+	def identifier(self) -> PortId:
+		"""
+		Get the unique identifier.
+		"""
+		return self._identifier
+
+	@abstractmethod
+	def signals(self) -> List[Signal]:
+		"""
+		Get a list of all connected signals.
+		"""
+		pass
+	
+	@abstractmethod
+	def signal_count(self) -> int:
+		"""
+		Get the number of connected signals.
+		"""
+		pass
+
+	@abstractmethod
+	def signal(self, i: int = 0) -> Signal:
+		"""
+		Get the connected signal at index i.
+		"""
+		pass
+
+	@abstractmethod
+	def connect(self, signal: Signal) -> None:
+		"""
+		Connect a signal.
+		"""
+		pass
+
+	@abstractmethod
+	def disconnect(self, i: int = 0) -> None:
+		"""
+		Disconnect a signal.
+		"""
+		pass
+
+	# TODO: More stuff.
+
+class InputPort(Port):
+	"""
+	Input port.
+	TODO: More info.
+	"""
+	_source_signal: Optional[Signal]
+
+	def __init__(self, identifier: PortId):
+		"""
+		Construct an InputPort.
+		"""
+		super().__init__(identifier)
+		self._source_signal = None
+
+	@final
+	def signals(self) -> List[Signal]:
+		return [] if self._source_signal == None else [self._source_signal]
+	
+	@final
+	def signal_count(self) -> int:
+		return 0 if self._source_signal == None else 1
+
+	@final
+	def signal(self, i: int = 0) -> Signal:
+		assert i >= 0 and i < self.signal_count() # TODO: Error message.
+		assert self._source_signal != None # TODO: Error message.
+		return self._source_signal
+
+	@final
+	def connect(self, signal: Signal) -> None:
+		self._source_signal = signal
+
+	@final
+	def disconnect(self, i: int = 0) -> None:
+		assert i >= 0 and i < self.signal_count() # TODO: Error message.
+		self._source_signal = None
+
+	# TODO: More stuff.
+
+class OutputPort(Port):
+	"""
+	Output port.
+	TODO: More info.
+	"""
+
+	_destination_signals: List[Signal]
+
+	def __init__(self, identifier: PortId):
+		"""
+		Construct an OutputPort.
+		"""
+		super().__init__(identifier)
+		self._destination_signals = []
+
+	@final
+	def signals(self) -> List[Signal]:
+		return self._destination_signals.copy()
+
+	@final
+	def signal_count(self) -> int:
+		return len(self._destination_signals)
+
+	@final
+	def signal(self, i: int = 0) -> Signal:
+		assert i >= 0 and i < self.signal_count() # TODO: Error message.
+		return self._destination_signals[i]
+
+	@final
+	def connect(self, signal: Signal) -> None:
+		assert signal not in self._destination_signals # TODO: Error message.
+		self._destination_signals.append(signal)
+	
+	@final
+	def disconnect(self, i: int = 0) -> None:
+		assert i >= 0 and i < self.signal_count() # TODO: Error message.
+		del self._destination_signals[i]
+		
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/b_asic/schema.py b/b_asic/schema.py
new file mode 100644
index 0000000000000000000000000000000000000000..a7642f49fcca42459b5ee04f069781e13605f517
--- /dev/null
+++ b/b_asic/schema.py
@@ -0,0 +1,24 @@
+"""
+B-ASIC Schema Module.
+TODO: More info.
+"""
+
+from b_asic.pc import PrecedenceChart
+
+class Schema:
+	"""
+	Schema constructed from a precedence chart.
+	TODO: More info.
+	"""
+
+	pc: PrecedenceChart
+	# TODO: More members.
+
+	def __init__(self, pc: PrecedenceChart):
+		"""
+		Construct a Schema.
+		"""
+		self.pc = pc
+		# TODO: Implement.
+
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/b_asic/sfg.py b/b_asic/sfg.py
new file mode 100644
index 0000000000000000000000000000000000000000..d39cc5245131f9815c8e495f1e9faebc024a190f
--- /dev/null
+++ b/b_asic/sfg.py
@@ -0,0 +1,37 @@
+"""
+B-ASIC Signal Flow Graph Module.
+TODO: More info.
+"""
+
+from b_asic.operation import OperationId, Operation, BasicOperation
+from b_asic.signal import SignalSource, SignalDestination
+from b_asic.simulation import SimulationState, OperationState
+from typing import List, final
+
+class SFG(BasicOperation):
+	"""
+	Signal flow graph.
+	TODO: More info.
+	"""
+
+	_operations: List[Operation]
+
+	def __init__(self, identifier: OperationId, input_destinations: List[SignalDestination], output_sources: List[SignalSource]):
+		"""
+		Construct a SFG.
+		"""
+		super().__init__(identifier)
+		# TODO: Allocate input/output ports with appropriate IDs.
+		self._operations = []
+		# TODO: Traverse the graph between the inputs/outputs and add to self._operations.
+		# TODO: Connect ports with signals with appropriate IDs.
+
+	@final
+	def evaluate(self, inputs: list) -> list:
+		return [] # TODO: Implement
+
+	@final
+	def split(self) -> List[Operation]:
+		return self._operations
+
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/b_asic/signal.py b/b_asic/signal.py
new file mode 100644
index 0000000000000000000000000000000000000000..36be9f58d6a9a9403fb034140c3b60958f436f85
--- /dev/null
+++ b/b_asic/signal.py
@@ -0,0 +1,68 @@
+"""
+B-ASIC Signal Module.
+TODO: More info.
+"""
+
+from b_asic.operation import Operation
+from typing import NewType
+
+SignalId = NewType("SignalId", int)
+
+class SignalSource:
+	"""
+	Handle to a signal source.
+	TODO: More info.
+	"""
+	operation: Operation
+	port_index: int
+
+	def __init__(self, operation: Operation, port_index: int):
+		"""
+		Construct a SignalSource.
+		"""
+		self.operation = operation
+		self.port_index = port_index
+
+	# TODO: More stuff.
+
+class SignalDestination:
+	"""
+	Handle to a signal destination.
+	TODO: More info.
+	"""
+	operation: Operation
+	port_index: int
+
+	def __init__(self, operation: Operation, port_index: int):
+		"""
+		Construct a SignalDestination.
+		"""
+		self.operation = operation
+		self.port_index = port_index
+
+	# TODO: More stuff.
+
+class Signal:
+	"""
+	A connection between two operations consisting of a source and destination handle.
+	TODO: More info.
+	"""
+	_identifier: SignalId
+	source: SignalSource
+	destination: SignalDestination
+
+	def __init__(self, identifier: SignalId, source: SignalSource, destination: SignalDestination):
+		"""
+		Construct a Signal.
+		"""
+		self._identifier = identifier
+		self.source = source
+		self.destination = destination
+
+	def identifier(self) -> SignalId:
+		"""
+		Get the unique identifier.
+		"""
+		return self._identifier
+
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/b_asic/simulation.py b/b_asic/simulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa33cb337d913bead6a7446ce093efdb86b09cb5
--- /dev/null
+++ b/b_asic/simulation.py
@@ -0,0 +1,42 @@
+"""
+B-ASIC Simulation Module.
+TODO: More info.
+"""
+
+from b_asic.operation import OperationId
+from numbers import Number
+from typing import List, Dict
+
+class OperationState:
+	"""
+	Simulation state of an operation.
+	TODO: More info.
+	"""
+
+	output_values: List[Number]
+	iteration: int
+
+	def __init__(self):
+		"""
+		Construct an OperationState.
+		"""
+		self.output_values = []
+		self.iteration = 0
+
+class SimulationState:
+	"""
+	Simulation state.
+	TODO: More info.
+	"""
+
+	operation_states: Dict[OperationId, OperationState]
+	iteration: int
+
+	def __init__(self):
+		"""
+		Construct a SimulationState.
+		"""
+		self.operation_states = {}
+		self.iteration = 0
+
+	# TODO: More stuff.
\ No newline at end of file
diff --git a/helloworld.py b/helloworld.py
deleted file mode 100644
index 6d95fe97a12449aa7e3cf570dea13203d07571b9..0000000000000000000000000000000000000000
--- a/helloworld.py
+++ /dev/null
@@ -1 +0,0 @@
-print("Hello world")
\ No newline at end of file
diff --git a/logo.png b/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..b1bd78fe7eb8a737ac8153576078d61492c2e9a3
Binary files /dev/null and b/logo.png differ
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa6d7a6c41247b4a4151d27d2e221c6d328851c6
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,75 @@
+import os
+import sys
+import shutil
+import subprocess
+import setuptools
+from setuptools import Extension
+from setuptools.command.build_ext import build_ext
+
+CMAKE_EXE = os.environ.get('CMAKE_EXE', shutil.which('cmake'))
+
+class CMakeExtension(Extension):
+    def __init__(self, name, sourcedir = ""):
+        super().__init__(name, sources=[])
+        self.sourcedir = os.path.abspath(sourcedir)
+
+class CMakeBuild(build_ext):
+    def build_extension(self, ext):
+        if not isinstance(ext, CMakeExtension):
+            return super().build_extension(ext)
+
+        if not CMAKE_EXE:
+            raise RuntimeError(f"Cannot build extension {ext.name}: CMake executable not found! Set the CMAKE_EXE environment variable or update your path.")
+
+        cmake_build_type = "Debug" if self.debug else "Release"
+        cmake_output_dir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
+        cmake_configure_argv = [
+            CMAKE_EXE, ext.sourcedir,
+            "-DCMAKE_BUILD_TYPE=" + cmake_build_type,
+            "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=" + cmake_output_dir,
+            "-DPYTHON_EXECUTABLE=" + sys.executable,
+        ]
+        cmake_build_argv = [
+            CMAKE_EXE, "--build", ".",
+            "--config", cmake_build_type
+        ]
+
+        if not os.path.exists(self.build_temp):
+            os.makedirs(self.build_temp)
+        
+        env = os.environ.copy()
+        
+        print(f"=== Configuring {ext.name} ===")
+        print(f"Temp dir: {self.build_temp}")
+        print(f"Output dir: {cmake_output_dir}")
+        subprocess.check_call(cmake_configure_argv, cwd=self.build_temp, env=env)
+
+        print(f"=== Building {ext.name} ===")
+        print(f"Temp dir: {self.build_temp}")
+        print(f"Output dir: {cmake_output_dir}")
+        print(f"Build type: {cmake_build_type}")
+        subprocess.check_call(cmake_build_argv, cwd=self.build_temp, env=env)
+
+        print()
+
+setuptools.setup(
+    name = "b-asic",
+    version = "0.0.1",
+    author = "Adam Jakobsson, Angus Lothian, Arvid Westerlund, Felix Goding, Ivar Härnqvist, Jacob Wahlman, Kevin Scott, Rasmus Karlsson",
+    author_email = "adaja901@student.liu.se, anglo547@student.liu.se, arvwe160@student.liu.se, felgo673@student.liu.se, ivaha717@student.liu.se, jacwa448@student.liu.se, kevsc634@student.liu.se, raska119@student.liu.se",
+    description = "Better ASIC Toolbox",
+    long_description = open("README.md", "r").read(),
+    long_description_content_type = "text/markdown",
+    url = "https://gitlab.liu.se/PUM_TDDD96/B-ASIC",
+    classifiers = [
+        "Programming Language :: Python :: 3",
+        "License :: OSI Approved :: MIT License",
+        "Operating System :: OS Independent",
+    ],
+    python_requires = ">=3.6",
+    install_requires = ["pybind11>=2.3.0"],
+    packages = ["b_asic"],
+    ext_modules = [CMakeExtension("b_asic")],
+    cmdclass = {"build_ext": CMakeBuild},
+    zip_safe = False
+)
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..75a77ef58b86cd29238205a078cec780a6ba9a36
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,21 @@
+#include <pybind11/pybind11.h>
+
+namespace py = pybind11;
+
+namespace asic {
+
+int add(int a, int b) {
+	return a + b;
+}
+
+int sub(int a, int b) {
+	return a - b;
+}
+
+} // namespace asic
+
+PYBIND11_MODULE(_b_asic, m) {
+	m.doc() = "Better ASIC Toolbox Extension Module.";
+	m.def("add", &asic::add, "A function which adds two numbers.", py::arg("a"), py::arg("b"));
+	m.def("sub", &asic::sub, "A function which subtracts two numbers.", py::arg("a"), py::arg("b"));
+}
\ No newline at end of file