Skip to content
Snippets Groups Projects
Commit 4555cad2 authored by Felix Goding's avatar Felix Goding
Browse files

Merge branch 'system_shell' into HEAD

# Conflicts:
#	.gitlab-ci.yml
#	README.md
parents f1b026aa 613e9098
No related branches found
No related tags found
4 merge requests!67WIP: B-ASIC version 1.0.0 hotfix,!65B-ASIC version 1.0.0,!15Add changes from sprint 1 and 2 to master,!1WIP: System shell to develop branch
.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
stages:
- build
PythonBuild:
stage: build
artifacts:
untracked: true
script:
- apt-get update && apt-get install python3 -y
\ No newline at end of file
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
include README.md
include LICENSE
include CMakeLists.txt
recursive-include src *.cpp *.h
<img src="https://files.slack.com/files-pri/TSHPRJY83-FTTRW9MQ8/b-asic-logo-opaque.png" width="318" height="100">
<br>
<h3>B-ASIC is an ASIC toolbox for Python 3 that simplifies circuit design and optimization.<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
"""
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
"""
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
"""
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
"""
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
"""
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
"""
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
"""
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
"""
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
"""
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
logo.png 0 → 100644
logo.png

69 KiB

setup.py 0 → 100644
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
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment