Added some code documentation and updated git action to generate it.

This commit is contained in:
honzastor 2021-03-31 04:40:54 +02:00
parent 7a6d5213f8
commit a336a683e7
18 changed files with 831 additions and 82 deletions

View File

@ -30,6 +30,8 @@ jobs:
run: python -c "import sys; print(sys.version)" run: python -c "import sys; print(sys.version)"
- name: Run generating - name: Run generating
run: python ariths_gen.py run: python ariths_gen.py
- name: Create documentation
run: pdoc --html ariths_gen
- name: Listing - name: Listing
run: ls build run: ls build
- name: Listing2 - name: Listing2

View File

@ -5,7 +5,9 @@
ArithsGen presents an open source tool that enables generation of various arithmetic circuits along with the possibility to export them to various representations which all serve their specific purpose. C language for easy simulation, Verilog for logic synthesis, BLIF for formal verification possibilities and CGP to enable further global optimization. ArithsGen presents an open source tool that enables generation of various arithmetic circuits along with the possibility to export them to various representations which all serve their specific purpose. C language for easy simulation, Verilog for logic synthesis, BLIF for formal verification possibilities and CGP to enable further global optimization.
### Usage ### Usage
```bash
python3 ariths_gen.py python3 ariths_gen.py
```
### Example of generation ### Example of generation
#Example of 8-bit unsigned dadda multiplier that uses rca to provide the final product #Example of 8-bit unsigned dadda multiplier that uses rca to provide the final product
@ -14,3 +16,16 @@ ArithsGen presents an open source tool that enables generation of various arithm
u_dadda = UnsignedDaddaMultiplier(a=a, b=b, prefix="h_u_dadda_rca8", unsigned_adder_class_name=UnsignedRippleCarryAdder) u_dadda = UnsignedDaddaMultiplier(a=a, b=b, prefix="h_u_dadda_rca8", unsigned_adder_class_name=UnsignedRippleCarryAdder)
u_dadda.get_v_code_hier(open("h_u_dadda_rca8.v", "w")) u_dadda.get_v_code_hier(open("h_u_dadda_rca8.v", "w"))
## Documentation
Code documentation is provided using **pdoc** documentation generator tool. Source: https://pdoc3.github.io/pdoc/.
### Instalation
```bash
pip3 install pdoc3
```
### Usage
```bash
pdoc --html ariths_gen
```

View File

@ -6,6 +6,10 @@ Script checks correct functionality of various architectures of unsigned/signed
**Note** that these circuits were manually modified to allow such a testing (added main with nested loops and asserts)! **Note** that these circuits were manually modified to allow such a testing (added main with nested loops and asserts)!
## Execute permission ## Execute permission
```bash
chmod +x c_tests.sh chmod +x c_tests.sh
```
## Usage ## Usage
```bash
./c_tests.sh ./c_tests.sh
```

View File

@ -14,8 +14,10 @@ from ariths_gen.wire_components import(
Bus Bus
) )
""" ARITHMETIC CIRCUITS """
class ArithmeticCircuit(): class ArithmeticCircuit():
"""Class represents a general arithmetic circuit and ensures their generation to various representations.
"""
def __init__(self): def __init__(self):
self.components = [] self.components = []
self.circuit_wires = [] self.circuit_wires = []

View File

@ -20,8 +20,11 @@ from ariths_gen.wire_components import(
import math import math
""" MULTIPLIER CIRCUITS """
class MultiplierCircuit(ArithmeticCircuit): class MultiplierCircuit(ArithmeticCircuit):
"""Class represents a general multiplier circuit derived from `ArithmeticCircuit` class.
"""
def __init__(self): def __init__(self):
super().__init__() super().__init__()

View File

@ -2,7 +2,10 @@ from .two_input_one_bit_circuit import(
TwoInputOneBitCircuit TwoInputOneBitCircuit
) )
class ThreeInputOneBitCircuit(TwoInputOneBitCircuit): class ThreeInputOneBitCircuit(TwoInputOneBitCircuit):
"""Class represents a general three input one bit circuit and implements their generation to various representations. It is derived from `TwoInputOneBitCircuit` class.
"""
def __init__(self): def __init__(self):
super().__init__() super().__init__()

View File

@ -2,7 +2,10 @@ from .arithmetic_circuit import(
ArithmeticCircuit ArithmeticCircuit
) )
class TwoInputOneBitCircuit(ArithmeticCircuit): class TwoInputOneBitCircuit(ArithmeticCircuit):
"""Class represents a general two input one bit circuit and implements their generation to various representations. It is derived from `ArithmeticCircuit` class.
"""
def __init__(self): def __init__(self):
super().__init__() super().__init__()

View File

@ -25,7 +25,39 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate NotGate
) )
class UnsignedCarryLookaheadAdder(ArithmeticCircuit): class UnsignedCarryLookaheadAdder(ArithmeticCircuit):
"""Class representing unsigned carry look-ahead adder.
Unsigned carry look-ahead adder represents faster adder circuit which is composed
of more complex circuitry but provides much less propagation delay as opposed to rca.
It is mainly composed of propagate/generate blocks and many AND/OR gates to calculate carries individually.
```
B3 A3 B2 A2 B1 A1 B0 A0
PG PG PG PG
block block block block
G3P3 G2P2 G1P1 G0P0
Carry Lookahead logic
Cout S3 S1 S0 S0
```
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of unsigned cla. Defaults to "u_cla".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "u_cla"): def __init__(self, a: Bus, b: Bus, prefix: str = "u_cla"):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -116,6 +148,38 @@ class UnsignedCarryLookaheadAdder(ArithmeticCircuit):
class SignedCarryLookaheadAdder(UnsignedCarryLookaheadAdder, ArithmeticCircuit): class SignedCarryLookaheadAdder(UnsignedCarryLookaheadAdder, ArithmeticCircuit):
"""Class representing signed carry look-ahead adder.
Signed carry look-ahead adder represents faster adder circuit which is composed
of more complex circuitry but provides much less propagation delay as opposed to rca.
It is mainly composed of propagate/generate blocks and many AND/OR gates to calculate carries individually.
At last XOR gates are used to ensure proper sign extension.
```
B3 A3 B2 A2 B1 A1 B0 A0
PG PG PG PG
block block block block
G3P3 G2P2 G1P1 G0P0
Carry Lookahead logic
with sign extension
Cout S3 S1 S0 S0
```
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of signed cla. Defaults to "s_cla".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "s_cla"): def __init__(self, a: Bus, b: Bus, prefix: str = "s_cla"):
super().__init__(a=a, b=b, prefix=prefix) super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t" self.c_data_type = "int64_t"

View File

@ -25,7 +25,43 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate NotGate
) )
class UnsignedPGRippleCarryAdder(ArithmeticCircuit): class UnsignedPGRippleCarryAdder(ArithmeticCircuit):
"""Class representing unsigned ripple carry adder with propagate/generate logic.
Unsigned ripple carry adder with PG logic represents slightly different rca implementation
of N-bit unsigned adder which is composed of N one bit full adders with P/G logic.
```
B3 A3 B2 A2 B1 A1 B0 A0
PG PG PG PG
FA FA FA FA
G3P3S3 G2P2S2 G1P1S1 G0P0S0
Group PG logic
Sum logic
Cout S3 S1 S0 S0
```
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of unsigned P/G rca. Defaults to "u_pg_rca".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "u_pg_rca"): def __init__(self, a: Bus, b: Bus, prefix: str = "u_pg_rca"):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -64,6 +100,42 @@ class UnsignedPGRippleCarryAdder(ArithmeticCircuit):
class SignedPGRippleCarryAdder(UnsignedPGRippleCarryAdder, ArithmeticCircuit): class SignedPGRippleCarryAdder(UnsignedPGRippleCarryAdder, ArithmeticCircuit):
"""Class representing signed ripple carry adder with propagate/generate logic.
Signed ripple carry adder with PG logic represents slightly different rca implementation
of N-bit signed adder which is composed of N one bit full adders with P/G logic.
At last XOR gates are used to ensure proper sign extension.
```
B3 A3 B2 A2 B1 A1 B0 A0
PG PG PG PG
FA FA FA FA
G3P3S3 G2P2S2 G1P1S1 G0P0S0
Group PG logic
Sum logic
with sign extension
Cout S3 S1 S0 S0
```
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of signed P/G rca. Defaults to "s_pg_rca".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "s_pg_rca"): def __init__(self, a: Bus, b: Bus, prefix: str = "s_pg_rca"):
super().__init__(a=a, b=b, prefix=prefix) super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t" self.c_data_type = "int64_t"

View File

@ -25,7 +25,34 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate NotGate
) )
class UnsignedRippleCarryAdder(ArithmeticCircuit): class UnsignedRippleCarryAdder(ArithmeticCircuit):
"""Class representing unsigned ripple carry adder.
Unsigned ripple carry adder represents N-bit unsigned adder which is composed of
N one bit adders, where first is a half adder and rest are full adders.
Its downside is its long propagation delay the bigger the circuit is.
```
B3 A3 B2 A2 B1 A1 B0 A0
C3 C2 C1
FA FA FA HA
Cout S3 S2 S1 S0
```
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of unsigned rca. Defaults to "u_rca".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "u_rca"): def __init__(self, a: Bus, b: Bus, prefix: str = "u_rca"):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -56,6 +83,33 @@ class UnsignedRippleCarryAdder(ArithmeticCircuit):
class SignedRippleCarryAdder(UnsignedRippleCarryAdder, ArithmeticCircuit): class SignedRippleCarryAdder(UnsignedRippleCarryAdder, ArithmeticCircuit):
"""Class representing signed ripple carry adder.
Signed ripple carry adder represents N-bit signed adder which is composed of
N one bit adders, where first is a half adder and rest are full adders.
At last XOR gates are used to ensure proper sign extension.
Its downside is its long propagation delay the bigger the circuit is.
```
B3 A3 B3 A3 B2 A2 B1 A1 B0 A0
SIGN C4 C3 C2 C1
Extend FA FA FA HA
Cout S3 S2 S1 S0
```
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of signed rca. Defaults to "s_rca".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "s_rca"): def __init__(self, a: Bus, b: Bus, prefix: str = "s_rca"):
super().__init__(a=a, b=b, prefix=prefix) super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t" self.c_data_type = "int64_t"

View File

@ -24,8 +24,23 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate NotGate
) )
# MULTIPLIERS
class UnsignedArrayMultiplier(MultiplierCircuit): class UnsignedArrayMultiplier(MultiplierCircuit):
"""Class representing unsigned array multiplier.
Unsigned array multiplier represents N-bit multiplier composed of
many AND gates and half/full adders to calculate partial products and
gradually sum them.
Downside is its rather big area because it is composed of many logic gates.
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of unsigned array multiplier. Defaults to "u_arrmul".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "u_arrmul"): def __init__(self, a: Bus, b: Bus, prefix: str = "u_arrmul"):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -85,6 +100,21 @@ class UnsignedArrayMultiplier(MultiplierCircuit):
class SignedArrayMultiplier(MultiplierCircuit): class SignedArrayMultiplier(MultiplierCircuit):
"""Class representing signed array multiplier.
Signed array multiplier represents N-bit multiplier composed of
many AND/NAND gates and half/full adders to calculate partial products and
gradually sum them.
Downside is its rather big area because it is composed of many logic gates.
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of signed array multiplier. Defaults to "s_arrmul".
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "s_arrmul"): def __init__(self, a: Bus, b: Bus, prefix: str = "s_arrmul"):
super().__init__() super().__init__()
self.c_data_type = "int64_t" self.c_data_type = "int64_t"

View File

@ -25,7 +25,26 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate NotGate
) )
class UnsignedDaddaMultiplier(MultiplierCircuit): class UnsignedDaddaMultiplier(MultiplierCircuit):
"""Class representing unsigned dadda multiplier.
Unsigned dadda multiplier represents fast N-bit multiplier which utilizes
the functionality of reduction algorithm proposed by Luigi Dadda.
Dadda algorithm is described more in detail here:
https://en.wikipedia.org/wiki/Dadda_multiplier
It is composed of much less inner components (half/full adders, AND gates) as opposed
to e.g. wallace and array multipliers.
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of unsigned dadda multiplier. Defaults to "u_dadda_rca".
unsigned_adder_class_name (str, optional): Unsigned multi bit adder used to obtain final sums of products. Defaults to UnsignedRippleCarryAdder.
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "u_dadda_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder): def __init__(self, a: Bus, b: Bus, prefix: str = "u_dadda_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -114,6 +133,25 @@ class UnsignedDaddaMultiplier(MultiplierCircuit):
class SignedDaddaMultiplier(MultiplierCircuit): class SignedDaddaMultiplier(MultiplierCircuit):
"""Class representing signed dadda multiplier.
Signed dadda multiplier represents fast N-bit multiplier which utilizes
the functionality of reduction algorithm proposed by Luigi Dadda and uses Baugh-Wooley algorithm
to perform signed multiplication.
Dadda algorithm is described more in detail here:
https://en.wikipedia.org/wiki/Dadda_multiplier
It is composed of much less inner components (half/full adders, AND/NAND gates) as opposed
to e.g. wallace and array multipliers.
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of signed dadda multiplier. Defaults to "s_dadda_rca".
unsigned_adder_class_name (str, optional): Unsigned multi bit adder used to obtain final sums of products. Defaults to UnsignedRippleCarryAdder.
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "s_dadda_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder): def __init__(self, a: Bus, b: Bus, prefix: str = "s_dadda_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)

View File

@ -25,7 +25,25 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate NotGate
) )
class UnsignedWallaceMultiplier(MultiplierCircuit): class UnsignedWallaceMultiplier(MultiplierCircuit):
"""Class representing unsigned wallace multiplier.
Unsigned wallace multiplier represents fast N-bit multiplier which utilizes
the functionality of wallace tree reduction algorithm proposed by Chris Wallace.
Wallace tree algorithm is described more in detail here:
https://en.wikipedia.org/wiki/Wallace_tree
It presents smaller circuit in area opposed to array multiplier but is slightly bigger then dadda because of less reduction stages.
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of unsigned wallace multiplier. Defaults to "u_wallace_rca".
unsigned_adder_class_name (str, optional): Unsigned multi bit adder used to obtain final sums of products. Defaults to UnsignedRippleCarryAdder.
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "u_wallace_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder): def __init__(self, a: Bus, b: Bus, prefix: str = "u_wallace_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -109,6 +127,24 @@ class UnsignedWallaceMultiplier(MultiplierCircuit):
class SignedWallaceMultiplier(MultiplierCircuit): class SignedWallaceMultiplier(MultiplierCircuit):
"""Class representing signed wallace multiplier.
Signed wallace multiplier represents fast N-bit multiplier which utilizes
the functionality of wallace tree reduction algorithm proposed by Chris Wallace and uses Baugh-Wooley algorithm
to perform signed multiplication.
Wallace tree algorithm is described more in detail here:
https://en.wikipedia.org/wiki/Wallace_tree
It presents smaller circuit in area opposed to array multiplier but is slightly bigger then dadda because of less reduction stages.
Description of the __init__ method.
Args:
a (Bus): First input bus.
b (Bus): Second input bus.
prefix (str, optional): Prefix name of signed wallace multiplier. Defaults to "s_wallace_rca".
unsigned_adder_class_name (str, optional): Unsigned multi bit adder used to obtain final sums of products. Defaults to UnsignedRippleCarryAdder.
"""
def __init__(self, a: Bus, b: Bus, prefix: str = "s_wallace_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder): def __init__(self, a: Bus, b: Bus, prefix: str = "s_wallace_rca", unsigned_adder_class_name: str = UnsignedRippleCarryAdder):
super().__init__() super().__init__()
self.N = max(a.N, b.N) self.N = max(a.N, b.N)

View File

@ -1,10 +1,25 @@
from ariths_gen.wire_components import Wire from ariths_gen.wire_components import Wire
""" LOGIC GATE COMPONENTS """
# Two-input # # Two-input #
class LogicGate(): class LogicGate():
"""Class representing two input logic gates.
```
FUNC
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "gate".
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "gate"): def __init__(self, a: Wire, b: Wire, prefix: str = "gate"):
self.a = Wire(name=prefix+"_"+a.name.replace(prefix+"_", ""), value=a.value) self.a = Wire(name=prefix+"_"+a.name.replace(prefix+"_", ""), value=a.value)
self.b = Wire(name=prefix+"_"+b.name.replace(prefix+"_", ""), value=b.value) self.b = Wire(name=prefix+"_"+b.name.replace(prefix+"_", ""), value=b.value)
@ -154,6 +169,23 @@ class LogicGate():
class InvertedLogicGate(LogicGate): class InvertedLogicGate(LogicGate):
"""Class representing two input inverted logic gates.
```
FUNC
O
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "gate".
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "gate"): def __init__(self, a: Wire, b: Wire, prefix: str = "gate"):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
@ -172,6 +204,24 @@ class InvertedLogicGate(LogicGate):
class AndGate(LogicGate): class AndGate(LogicGate):
"""Class representing two input and gate.
```
&
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
self.gate_type = "and_gate" self.gate_type = "and_gate"
@ -186,6 +236,24 @@ class AndGate(LogicGate):
class NandGate(InvertedLogicGate): class NandGate(InvertedLogicGate):
"""Class representing two input nand gate.
```
&
O
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
self.gate_type = "nand_gate" self.gate_type = "nand_gate"
@ -200,6 +268,24 @@ class NandGate(InvertedLogicGate):
class OrGate(LogicGate): class OrGate(LogicGate):
"""Class representing two input or gate.
```
1
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
self.gate_type = "or_gate" self.gate_type = "or_gate"
@ -214,6 +300,24 @@ class OrGate(LogicGate):
class NorGate(InvertedLogicGate): class NorGate(InvertedLogicGate):
"""Class representing two input nor gate.
```
1
O
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
self.gate_type = "nor_gate" self.gate_type = "nor_gate"
@ -228,6 +332,24 @@ class NorGate(InvertedLogicGate):
class XorGate(LogicGate): class XorGate(LogicGate):
"""Class representing two input xor gate.
```
=1
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
self.gate_type = "xor_gate" self.gate_type = "xor_gate"
@ -242,6 +364,24 @@ class XorGate(LogicGate):
class XnorGate(InvertedLogicGate): class XnorGate(InvertedLogicGate):
"""Class representing two input xnor gate.
```
=1
O
```
Description of the __init__ method.
Args:
a (Wire): First input wire.
b (Wire): Second input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, b: Wire, prefix: str = "", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)
self.gate_type = "xnor_gate" self.gate_type = "xnor_gate"
@ -257,6 +397,23 @@ class XnorGate(InvertedLogicGate):
# Single-input # # Single-input #
class NotGate(InvertedLogicGate): class NotGate(InvertedLogicGate):
"""Class representing one input not gate.
```
1
O
```
Description of the __init__ method.
Args:
a (Wire): Input wire.
prefix (str, optional): Prefix name of logic gate. Defaults to "".
outid (int, optional): Index of output wire. Defaults to 0.
"""
def __init__(self, a: Wire, prefix: str = "", outid: int = 0): def __init__(self, a: Wire, prefix: str = "", outid: int = 0):
self.gate_type = "not_gate" self.gate_type = "not_gate"
self.cgp_function = 1 self.cgp_function = 1

View File

@ -2,8 +2,26 @@ from ariths_gen.core import ThreeInputOneBitCircuit
from ariths_gen.one_bit_circuits.logic_gates import LogicGate, AndGate, NandGate, OrGate, NorGate, XorGate, XnorGate, NotGate from ariths_gen.one_bit_circuits.logic_gates import LogicGate, AndGate, NandGate, OrGate, NorGate, XorGate, XnorGate, NotGate
from ariths_gen.wire_components import Wire, Bus from ariths_gen.wire_components import Wire, Bus
# THREE INPUT CIRCUITS
class FullAdder(ThreeInputOneBitCircuit): class FullAdder(ThreeInputOneBitCircuit):
"""Class representing three input one bit full adder.
```
Sum
Cout
```
Description of the __init__ method.
Args:
a (Wire, optional): First input wire. Defaults to Wire(name="a").
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
c (Wire, optional): Carry input wire. Defaults to Wire(name="cin").
prefix (str, optional): Prefix name of full adder. Defaults to "fa".
"""
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="cin"), prefix: str = "fa"): def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="cin"), prefix: str = "fa"):
super().__init__() super().__init__()
self.c_data_type = "uint8_t" self.c_data_type = "uint8_t"
@ -38,6 +56,24 @@ class FullAdder(ThreeInputOneBitCircuit):
class FullAdderPG(ThreeInputOneBitCircuit): class FullAdderPG(ThreeInputOneBitCircuit):
"""Class representing modified three input one bit full adder with propagate/generate logic.
```
P
G
Sum
```
Description of the __init__ method.
Args:
a (Wire, optional): First input wire. Defaults to Wire(name="a").
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
c (Wire, optional): Carry input wire. Defaults to Wire(name="cin").
prefix (str, optional): Prefix name of full adder. Defaults to "fa_cla".
"""
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="cin"), prefix: str = "fa_cla"): def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="cin"), prefix: str = "fa_cla"):
super().__init__() super().__init__()
self.c_data_type = "uint8_t" self.c_data_type = "uint8_t"

View File

@ -2,8 +2,25 @@ from ariths_gen.core import TwoInputOneBitCircuit
from ariths_gen.one_bit_circuits.logic_gates import LogicGate, AndGate, NandGate, OrGate, NorGate, XorGate, XnorGate, NotGate from ariths_gen.one_bit_circuits.logic_gates import LogicGate, AndGate, NandGate, OrGate, NorGate, XorGate, XnorGate, NotGate
from ariths_gen.wire_components import Wire, Bus from ariths_gen.wire_components import Wire, Bus
# TWO INPUT CIRCUITS
class HalfAdder(TwoInputOneBitCircuit): class HalfAdder(TwoInputOneBitCircuit):
"""Class representing two input one bit half adder.
```
Sum
Cout
```
Description of the __init__ method.
Args:
a (Wire, optional): First input wire. Defaults to Wire(name="a").
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
prefix (str, optional): Prefix name of full adder. Defaults to "ha".
"""
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "ha"): def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "ha"):
super().__init__() super().__init__()
self.c_data_type = "uint8_t" self.c_data_type = "uint8_t"
@ -27,6 +44,23 @@ class HalfAdder(TwoInputOneBitCircuit):
class PGLogicBlock(TwoInputOneBitCircuit): class PGLogicBlock(TwoInputOneBitCircuit):
"""Class representing two input one bit propagate/generate logic block.
```
P
G
```
Description of the __init__ method.
Args:
a (Wire, optional): First input wire. Defaults to Wire(name="a").
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
prefix (str, optional): Prefix name of full adder. Defaults to "pg_logic".
"""
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "pg_logic"): def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "pg_logic"):
super().__init__() super().__init__()
self.c_data_type = "uint8_t" self.c_data_type = "uint8_t"
@ -57,7 +91,25 @@ class PGLogicBlock(TwoInputOneBitCircuit):
def get_sum_wire(self): def get_sum_wire(self):
return self.out.get_wire(2) return self.out.get_wire(2)
class ConstantWireValue0(TwoInputOneBitCircuit): class ConstantWireValue0(TwoInputOneBitCircuit):
"""Class representing two input one bit constant wire with value 0 generation block.
```
0
```
Description of the __init__ method.
Args:
a (Wire, optional): First input wire. Defaults to Wire(name="a").
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
prefix (str, optional): Prefix name of full adder. Defaults to "constant_wire_value_0".
"""
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "constant_wire_value_0"): def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "constant_wire_value_0"):
super().__init__() super().__init__()
self.c_data_type = "uint8_t" self.c_data_type = "uint8_t"
@ -83,6 +135,23 @@ class ConstantWireValue0(TwoInputOneBitCircuit):
class ConstantWireValue1(TwoInputOneBitCircuit): class ConstantWireValue1(TwoInputOneBitCircuit):
"""Class representing two input one bit constant wire with value 1 generation block.
```
1
```
Description of the __init__ method.
Args:
a (Wire, optional): First input wire. Defaults to Wire(name="a").
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
prefix (str, optional): Prefix name of full adder. Defaults to "constant_wire_value_1".
"""
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "constant_wire_value_1"): def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "constant_wire_value_1"):
super().__init__() super().__init__()
self.c_data_type = "uint8_t" self.c_data_type = "uint8_t"

View File

@ -1,7 +1,17 @@
from .wires import Wire from .wires import Wire
class Bus(): class Bus():
def __init__(self, prefix: str, N: int = 1, wires_list: list = None): """Class representing bus of wires used as inputs/outputs of bigger circuits.
Description of the __init__ method.
Args:
prefix (str, optional): Prefix name of the bus. Defaults to "bus".
N (int, optional): Number of wires in the bus. Defaults to 1.
wires_list (list, optional): List of Wire objects used to clone one bus to another. Defaults to 0.
"""
def __init__(self, prefix: str = "bus", N: int = 1, wires_list: list = None):
if wires_list is None: if wires_list is None:
self.bus = [Wire(name=prefix+"_"+str(i), index=i) for i in range(N)] self.bus = [Wire(name=prefix+"_"+str(i), index=i) for i in range(N)]
self.prefix = prefix self.prefix = prefix
@ -13,45 +23,119 @@ class Bus():
# Connecting output wire of the inner circuit component to the input of another component # Connecting output wire of the inner circuit component to the input of another component
# (or to the wire of the circuit's output bus) # (or to the wire of the circuit's output bus)
def connect(self, out_wire_index: int, inner_component_out_wire: Wire): def connect(self, bus_wire_index: int, inner_component_out_wire: Wire):
self.bus[out_wire_index] = inner_component_out_wire """Connects given 'Wire' object to a 'bus_wire_index' within this bus.
Args:
bus_wire_index (int): Index in bus to store given wire in.
inner_component_out_wire (Wire): Wire of some other component (mostly its output) to store in the bus.
"""
self.bus[bus_wire_index] = inner_component_out_wire
def get_wire(self, wire_index: int = 0): def get_wire(self, wire_index: int = 0):
"""Retrieves a wire from the bus by a given index.
Args:
wire_index (int, optional): Index of wire to retrieve from the bus. Defaults to 0.
Returns:
Wire: Return wire from the bus.
"""
return self.bus[wire_index] return self.bus[wire_index]
def bus_extend(self, N: int, prefix: str = "bus"): def bus_extend(self, N: int, prefix: str = "bus"):
"""Provides bus extension to contain more wires.
Args:
N (int): Number of wires in the bus. Defaults to 1.
prefix (str, optional): Prefix name of the bus. Defaults to "bus".
"""
if self.N < N: if self.N < N:
self.bus += [Wire(name=prefix+"_"+str(i), index=i) for i in range(self.N, N)] self.bus += [Wire(name=prefix+"_"+str(i), index=i) for i in range(self.N, N)]
self.N = N self.N = N
""" C CODE GENERATION """ """ C CODE GENERATION """
def get_declaration_c(self): def get_declaration_c(self):
"""Bus declaration in C code.
Returns:
str: C code for declaration and initialization of bus name.
"""
if self.N > 8: if self.N > 8:
return f" uint64_t {self.prefix} = 0;\n" return f" uint64_t {self.prefix} = 0;\n"
else: else:
return f" uint8_t {self.prefix} = 0;\n" return f" uint8_t {self.prefix} = 0;\n"
def get_wire_declaration_c(self): def get_wire_declaration_c(self):
"""Declare each wire from the bus independently.
Returns:
str: C code for declaration and initialization of bus wires.
"""
return "".join([w.get_declaration_c() for w in self.bus]) return "".join([w.get_declaration_c() for w in self.bus])
def get_wire_assign_c(self, bus_prefix: str = ""): def get_wire_assign_c(self, bus_prefix: str = ""):
"""Assign all bits from the bus to each individual wires in C code.
Args:
bus_prefix (str, optional): Custom bus prefix to use for assignment. Defaults to "".
Returns:
str: C code for bus wires assignments.
"""
bus_prefix = self.prefix if bus_prefix == "" else bus_prefix bus_prefix = self.prefix if bus_prefix == "" else bus_prefix
return "".join([w.get_assign_c(name=w.get_wire_value_c(name=bus_prefix, offset=self.bus.index(w))) for w in self.bus]) return "".join([w.get_assign_c(name=w.get_wire_value_c(name=bus_prefix, offset=self.bus.index(w))) for w in self.bus])
def return_wire_value_c(self, offset: int = 0): def return_wire_value_c(self, offset: int = 0):
"""Retrieve wire value from desired index position in the bus.
Args:
offset (int, optional): Offset position of the wire to be retrieved. Defaults to 0.
"""
self.get_wire(wire_index=offset).return_wire_value_c(offset=offset) self.get_wire(wire_index=offset).return_wire_value_c(offset=offset)
""" VERILOG CODE GENERATION """ """ VERILOG CODE GENERATION """
def get_wire_declaration_v(self): def get_wire_declaration_v(self):
"""Declare each wire from the bus independently.
Returns:
str: Verilog code for declaration of bus wires.
"""
return "".join([w.get_declaration_v() for w in self.bus]) return "".join([w.get_declaration_v() for w in self.bus])
def get_wire_assign_v(self, bus_prefix: str = ""): def get_wire_assign_v(self, bus_prefix: str = ""):
"""Assign all bits from the bus to each individual wires in Verilog code.
Args:
bus_prefix (str, optional): Custom bus prefix to use for assignment. Defaults to "".
Returns:
str: Verilog code for bus wires assignments.
"""
bus_prefix = self.prefix if bus_prefix == "" else bus_prefix bus_prefix = self.prefix if bus_prefix == "" else bus_prefix
return "".join([w.get_assign_v(name=self.prefix, offset=self.bus.index(w), array=True) for w in self.bus]) return "".join([w.get_assign_v(name=self.prefix, offset=self.bus.index(w), array=True) for w in self.bus])
""" BLIF CODE GENERATION """ """ BLIF CODE GENERATION """
def get_wire_declaration_blif(self, array: bool = True): def get_wire_declaration_blif(self, array: bool = True):
"""Declare each wire from the bus independently.
Argument `array` specifies whether to declare wires from bus by their offset e.g. out[0]
or by their wire name e.g. out_0.
Args:
array (bool, optional): Determines in which manner bus wire names are declared. Defaults to True.
Returns:
str: Blif code for declaration of bus wires.
"""
return "".join([w.get_declaration_blif(name=self.prefix, offset=self.bus.index(w), array=array) for w in self.bus]) return "".join([w.get_declaration_blif(name=self.prefix, offset=self.bus.index(w), array=array) for w in self.bus])
def get_wire_assign_blif(self, output: bool = False): def get_wire_assign_blif(self, output: bool = False):
"""Assign all bits from the bus as each individual wires in Blif code.
Args:
output (bool, optional): Specifies whether bus wires are used as outputs (assigned to) or as inputs (assigned from). Defaults to False.
Returns:
str: Blif code for bus wires assignments.
"""
return "".join([w.get_assign_blif(name=self.prefix+f"[{self.bus.index(w)}]", output=output) for w in self.bus]) return "".join([w.get_assign_blif(name=self.prefix+f"[{self.bus.index(w)}]", output=output) for w in self.bus])

View File

@ -1,4 +1,14 @@
class Wire(): class Wire():
"""Class representing basic wire used to interconnect components.
Description of the __init__ method.
Args:
name (str): Name of the wire.
value (int, optional): Value it carries (0,1). Defaults to 0.
index (int, optional): Index position of wire (mainly used for indexing within a bus). Defaults to 0.
"""
def __init__(self, name: str, value: int = 0, index: int = 0): def __init__(self, name: str, value: int = 0, index: int = 0):
self.name = name self.name = name
if self.name.endswith("_"+str(index)): if self.name.endswith("_"+str(index)):
@ -10,23 +20,68 @@ class Wire():
""" C CODE GENERATION """ """ C CODE GENERATION """
def get_declaration_c(self): def get_declaration_c(self):
"""Wire declaration in C code.
Returns:
str: C code for declaration and initialization of wire's name.
"""
return f" uint8_t {self.name} = {self.value};\n" return f" uint8_t {self.name} = {self.value};\n"
def get_wire_value_c(self, name: str = "", offset: int = 0): def get_wire_value_c(self, name: str = "", offset: int = 0):
"""Access desired bit from wire represented in C code variable.
Args:
name (str, optional): Name representing a wire. Defaults to "".
offset (int, optional): Access desired wire bit from C code variable (used to access wire bits from buses). Defaults to 0.
Returns:
str: C code bitwise shift to get bit from `offset` position in `w_name`.
"""
w_name = self.name if name == "" else name w_name = self.name if name == "" else name
return f"(({w_name} >> {offset}) & 0x01)" return f"(({w_name} >> {offset}) & 0x01)"
def get_assign_c(self, name: str): def get_assign_c(self, name: str):
"""Assign (connect) the value of wire to another wire.
Args:
name (str): Name of wire to assign value from.
Returns:
str: C code for assignment of one wire to another.
"""
return f" {self.name} = {name};\n" return f" {self.name} = {name};\n"
def return_wire_value_c(self, offset: int = 0): def return_wire_value_c(self, offset: int = 0):
"""Retrieve bit value from wire and shift it to desired position for storing it within a bus.
Args:
offset (int, optional): Used to shift wire value in order to be stored in proper location in bus. Defaults to 0.
Returns:
str: C code bitwise shift of retrieved wire value.
"""
return f"({self.name} & 0x01) << {offset}" return f"({self.name} & 0x01) << {offset}"
""" VERILOG CODE GENERATION """ """ VERILOG CODE GENERATION """
def get_declaration_v(self): def get_declaration_v(self):
"""Wire declaration in Verilog code.
Returns:
str: Verilog code for declaration of wire's name.
"""
return f" wire {self.name};\n" return f" wire {self.name};\n"
def get_assign_v(self, name: str, offset: int = 0, array: bool = False): def get_assign_v(self, name: str, offset: int = 0, array: bool = False):
"""Assignment of wire value to another desired wire in Verilog.
Args:
name (str): Name of wire/bus to assign value from.
offset (int, optional): Used to retrieve desired wire from a bus. Defaults to 0.
array (bool, optional): Tells whether wire value is assigned from within a bus or from basic wire. Defaults to False.
Returns:
str: Verilog code for wire assignment.
"""
if array is True: if array is True:
return f" assign {self.name} = {name}[{offset}];\n" return f" assign {self.name} = {name}[{offset}];\n"
else: else:
@ -34,12 +89,34 @@ class Wire():
""" BLIF CODE GENERATION """ """ BLIF CODE GENERATION """
def get_declaration_blif(self, name: str = "", offset: int = 0, array: bool = False): def get_declaration_blif(self, name: str = "", offset: int = 0, array: bool = False):
"""Wire declaration in Blif code.
Declares basic wire name if wire is not a part of a bus,
or declares wire by an offset of its position within the input bus.
Args:
name (str, optional): Name of a bus to be declared (if array is True). Defaults to "".
offset (int, optional): Offset wire location within a bus. Defaults to 0.
array (bool, optional): Tells whether a basic wire or a wire from within a bus is to be declared. Defaults to False.
Returns:
str: Blif code for declaration of a wire.
"""
if array is True: if array is True:
return f" {name}[{offset}]" return f" {name}[{offset}]"
else: else:
return f" {self.name}" return f" {self.name}"
def get_assign_blif(self, name: str, output: bool = False): def get_assign_blif(self, name: str, output: bool = False):
"""Assignment of wire value to another desired wire in Blif.
Args:
name (str): Name of the source/destination wire to be assigned to.
output (bool, optional): Whether 'name' represents the destination or the source wire in the assignment. Defaults to False.
Returns:
str: Blif code for assignment of one wire to another.
"""
if output is True: if output is True:
return f".names {self.name} {name}\n" + \ return f".names {self.name} {name}\n" + \
f"1 1\n" f"1 1\n"