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)"
- name: Run generating
run: python ariths_gen.py
- name: Create documentation
run: pdoc --html ariths_gen
- name: Listing
run: ls build
- 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.
### Usage
python3 ariths_gen.py
```bash
python3 ariths_gen.py
```
### Example of generation
#Example of 8-bit unsigned dadda multiplier that uses rca to provide the final product
@ -13,4 +15,17 @@ ArithsGen presents an open source tool that enables generation of various arithm
b = Bus(N=8, prefix="b_bus")
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)!
## Execute permission
chmod +x c_tests.sh
```bash
chmod +x c_tests.sh
```
## Usage
./c_tests.sh
```bash
./c_tests.sh
```

View File

@ -1,4 +1,4 @@
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -6,16 +6,18 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NorGate,
XorGate,
XnorGate,
NotGate
NotGate
)
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
""" ARITHMETIC CIRCUITS """
class ArithmeticCircuit():
"""Class represents a general arithmetic circuit and ensures their generation to various representations.
"""
def __init__(self):
self.components = []
self.circuit_wires = []
@ -176,7 +178,7 @@ class ArithmeticCircuit():
def get_function_block_c(self):
# Obtain proper adder name with its bit width
adder_prefix = self.__class__(a=Bus("a") , b=Bus("b")).prefix + str(self.N)
adder_prefix = self.__class__(a=Bus("a"), b=Bus("b")).prefix + str(self.N)
adder_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(N=self.N, prefix="b"), prefix=adder_prefix)
return f"{adder_block.get_circuit_c()}\n\n"
@ -264,7 +266,7 @@ class ArithmeticCircuit():
def get_function_block_v(self):
# Obtain proper adder name with its bit width
adder_prefix = self.__class__(a=Bus("a") , b=Bus("b")).prefix + str(self.N)
adder_prefix = self.__class__(a=Bus("a"), b=Bus("b")).prefix + str(self.N)
adder_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(N=self.N, prefix="b"), prefix=adder_prefix)
return f"{adder_block.get_circuit_v()}\n\n"
@ -369,7 +371,7 @@ class ArithmeticCircuit():
def get_function_block_blif(self):
# Obtain proper adder name with its bit width
adder_prefix = self.__class__(a=Bus("a") , b=Bus("b")).prefix + str(self.N)
adder_prefix = self.__class__(a=Bus("a"), b=Bus("b")).prefix + str(self.N)
adder_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(N=self.N, prefix="b"), prefix=adder_prefix)
return f"{adder_block.get_circuit_blif()}"
@ -397,4 +399,4 @@ class ArithmeticCircuit():
file_object.write(self.get_parameters_cgp())
file_object.write(self.get_triplet_cgp())
file_object.write(self.get_output_cgp())
file_object.close()
file_object.close()

View File

@ -1,8 +1,8 @@
from .arithmetic_circuit import(
from .arithmetic_circuit import (
ArithmeticCircuit
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -10,18 +10,21 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NorGate,
XorGate,
XnorGate,
NotGate
NotGate
)
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
import math
""" MULTIPLIER CIRCUITS """
class MultiplierCircuit(ArithmeticCircuit):
"""Class represents a general multiplier circuit derived from `ArithmeticCircuit` class.
"""
def __init__(self):
super().__init__()
@ -84,7 +87,7 @@ class MultiplierCircuit(ArithmeticCircuit):
column[-1] = NandGate(a=column[-1][0], b=column[-1][1], prefix=self.prefix+'_nand_'+str(column[-1][0].index)+'_'+str(column[-1][1].index))
if len(column[2:-1]) != 0:
column[2:-1] = [AndGate(a=column[i][0], b=column[i][1], prefix=self.prefix+'_and_'+str(column[i][0].index)+'_'+str(column[i][1].index)) for i in range(2, len(column)-1)]
return column
def get_column_height(self, column_num: int):

View File

@ -1,8 +1,11 @@
from .two_input_one_bit_circuit import(
from .two_input_one_bit_circuit import (
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):
super().__init__()
@ -17,7 +20,7 @@ class ThreeInputOneBitCircuit(TwoInputOneBitCircuit):
def get_out_invocation_c(self, **kwargs):
circuit_class = self.__class__()
return "".join([f' {o.name} = ({circuit_class.prefix}({self.a.name}, {self.b.name}, {self.c.name}) >> {self.out.bus.index(o)}) & 0x01;\n' for o in self.out.bus])
""" VERILOG CODE GENERATION """
# FLAT VERILOG #
# Module prototype with three inputs
@ -49,4 +52,4 @@ class ThreeInputOneBitCircuit(TwoInputOneBitCircuit):
# Chromosome prototype with three inputs
def get_parameters_cgp(self):
self.circuit_gates = self.get_circuit_gates()
return f"{{3,2,1,{len(self.circuit_gates)},2,1,0}}"
return f"{{3,2,1,{len(self.circuit_gates)},2,1,0}}"

View File

@ -1,8 +1,11 @@
from .arithmetic_circuit import(
from .arithmetic_circuit import (
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):
super().__init__()
@ -17,7 +20,7 @@ class TwoInputOneBitCircuit(ArithmeticCircuit):
# Wires values initialization and assignment
def get_init_c_flat(self):
return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_",""))) for i in self.inputs]) + \
return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_", ""))) for i in self.inputs]) + \
"".join([f" {c.out.name} = {c.get_init_c_flat()};\n" for c in self.components])
# Generating flat C code representation of circuit
@ -51,7 +54,7 @@ class TwoInputOneBitCircuit(ArithmeticCircuit):
return "".join([c[0].get_declaration_c() for c in self.circuit_wires])
def get_init_c_hier(self):
return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_",""))) for i in self.inputs]) + \
return "".join([i.get_assign_c(name=i.get_wire_value_c(name=i.name.replace(self.prefix+"_", ""))) for i in self.inputs]) + \
"".join([f" {c.out.name} = {c.get_gate_invocation_c(remove_prefix=False)}" for c in self.components])
def get_function_out_c_hier(self):
@ -69,7 +72,7 @@ class TwoInputOneBitCircuit(ArithmeticCircuit):
# Wires values initialization and assignment
def get_init_v_flat(self):
return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_","")) for i in self.inputs]) + \
return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_", "")) for i in self.inputs]) + \
"".join([f" assign {c.out.name} = {c.get_init_v_flat()};\n" for c in self.components])
# Generating flat Verilog code representation of circuit
@ -100,7 +103,7 @@ class TwoInputOneBitCircuit(ArithmeticCircuit):
return "".join([c[0].get_declaration_v() for c in self.circuit_wires if c[0] not in self.out.bus])
def get_init_v_hier(self):
return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_","")) for i in self.inputs])
return "".join([i.get_assign_v(name=i.name.replace(self.prefix+"_", "")) for i in self.inputs])
def get_function_out_v_hier(self):
return "".join([f"{c.get_gate_invocation_v(remove_prefix=False)}" for c in self.components])
@ -114,7 +117,7 @@ class TwoInputOneBitCircuit(ArithmeticCircuit):
def get_wire_mapping_blif(self):
# For unique mapping of all circuit's input interconnections
self.get_circuit_wires()
return "".join([i.get_assign_blif(name=i.name.replace(self.prefix+"_","")) for i in self.inputs])
return "".join([i.get_assign_blif(name=i.name.replace(self.prefix+"_", "")) for i in self.inputs])
def get_function_blif_flat(self):
return f"{self.get_wire_mapping_blif()}"+"".join([c.get_function_blif_flat() for c in self.components])
@ -141,4 +144,4 @@ class TwoInputOneBitCircuit(ArithmeticCircuit):
# FLAT CGP #
def get_parameters_cgp(self):
self.circuit_gates = self.get_circuit_gates()
return f"{{2,2,1,{len(self.circuit_gates)},2,1,0}}"
return f"{{2,2,1,{len(self.circuit_gates)},2,1,0}}"

View File

@ -1,12 +1,12 @@
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
from ariths_gen.core import(
from ariths_gen.core import (
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
PGLogicBlock,
ConstantWireValue0,
@ -14,7 +14,7 @@ from ariths_gen.one_bit_circuits.one_bit_components import(
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -25,7 +25,39 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate
)
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"):
super().__init__()
self.N = max(a.N, b.N)
@ -49,7 +81,7 @@ class UnsignedCarryLookaheadAdder(ArithmeticCircuit):
self.add_component(constant_wire_0)
# Used as a first generate wire for obtaining next carry bits
self.generate.append(constant_wire_0.out.get_wire())
# Gradual addition of propagate/generate logic blocks and AND/OR gates for Cout bits generation, XOR gates for Sum bits generation
for input_index in range(self.N):
pg_block = PGLogicBlock(self.a.get_wire(input_index), self.b.get_wire(input_index), prefix=self.prefix+"_pg_logic"+str(input_index))
@ -73,7 +105,7 @@ class UnsignedCarryLookaheadAdder(ArithmeticCircuit):
obj_sum_xor = XorGate(pg_block.get_sum_wire(), self.get_previous_component(2).out, prefix=self.prefix+"_xor"+str(input_index))
self.add_component(obj_sum_xor)
self.out.connect(input_index, obj_sum_xor.out)
# For each pg pair values algorithmically combine two input AND gates to replace multiple input gates (resolves fan-in issue)
composite_and_gates = []
# And combine AND gate pairs into OR gates
@ -100,22 +132,54 @@ class UnsignedCarryLookaheadAdder(ArithmeticCircuit):
composite_and_gates.append(obj_and)
composite_or_gates.append(composite_and_gates.pop())
# Final OR gates cascade using generated AND gates representing multiple input AND gates (cascade of multiple two input ones)
for a in range(len(composite_or_gates)-1):
obj_or = OrGate(self.get_previous_component().out, composite_or_gates[a].out, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=OrGate)))
self.add_component(obj_or)
# Carry bit generation
obj_cout_or = OrGate(pg_block.get_generate_wire(), self.get_previous_component().out, prefix=self.prefix+"_or"+str(self.get_instance_num(cls=OrGate)))
self.add_component(obj_cout_or)
# Connecting last output bit to last cout
if input_index == (self.N-1):
self.out.connect(self.N, obj_cout_or.out)
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"):
super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t"
@ -125,4 +189,4 @@ class SignedCarryLookaheadAdder(UnsignedCarryLookaheadAdder, ArithmeticCircuit):
self.add_component(sign_xor_1)
sign_xor_2 = XorGate(sign_xor_1.out, self.get_previous_component(2).out, prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=XorGate)))
self.add_component(sign_xor_2)
self.out.connect(self.N, sign_xor_2.out)
self.out.connect(self.N, sign_xor_2.out)

View File

@ -1,12 +1,12 @@
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
from ariths_gen.core import(
from ariths_gen.core import (
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
PGLogicBlock,
ConstantWireValue0,
@ -14,7 +14,7 @@ from ariths_gen.one_bit_circuits.one_bit_components import(
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -25,7 +25,43 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate
)
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"):
super().__init__()
self.N = max(a.N, b.N)
@ -49,7 +85,7 @@ class UnsignedPGRippleCarryAdder(ArithmeticCircuit):
obj_fa_cla = FullAdderPG(self.a.get_wire(input_index), self.b.get_wire(input_index), constant_wire_0.out.get_wire(), prefix=self.prefix+"_fa"+str(input_index))
else:
obj_fa_cla = FullAdderPG(self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().out, prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa_cla)
self.out.connect(input_index, obj_fa_cla.get_sum_wire())
@ -57,13 +93,49 @@ class UnsignedPGRippleCarryAdder(ArithmeticCircuit):
obj_or = OrGate(obj_and.out, self.get_previous_component().get_generate_wire(), prefix=self.prefix+"_or"+str(input_index))
self.add_component(obj_and)
self.add_component(obj_or)
# Connecting last output bit to last cout
if input_index == (self.N-1):
self.out.connect(self.N, obj_or.out)
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"):
super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t"
@ -73,4 +145,4 @@ class SignedPGRippleCarryAdder(UnsignedPGRippleCarryAdder, ArithmeticCircuit):
self.add_component(sign_xor_1)
sign_xor_2 = XorGate(sign_xor_1.out, self.get_previous_component(2).out, prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=XorGate)))
self.add_component(sign_xor_2)
self.out.connect(self.N, sign_xor_2.out)
self.out.connect(self.N, sign_xor_2.out)

View File

@ -1,12 +1,12 @@
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
from ariths_gen.core import(
from ariths_gen.core import (
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
PGLogicBlock,
ConstantWireValue0,
@ -14,7 +14,7 @@ from ariths_gen.one_bit_circuits.one_bit_components import(
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -25,7 +25,34 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate
)
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"):
super().__init__()
self.N = max(a.N, b.N)
@ -48,14 +75,41 @@ class UnsignedRippleCarryAdder(ArithmeticCircuit):
# Rest adders are full adders
else:
obj_adder = FullAdder(self.a.get_wire(input_index), self.b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_adder)
self.out.connect(input_index, obj_adder.get_sum_wire())
if input_index == (self.N-1):
self.out.connect(self.N, obj_adder.get_carry_wire())
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"):
super().__init__(a=a, b=b, prefix=prefix)
self.c_data_type = "int64_t"
@ -65,4 +119,4 @@ class SignedRippleCarryAdder(UnsignedRippleCarryAdder, ArithmeticCircuit):
self.add_component(sign_xor_1)
sign_xor_2 = XorGate(sign_xor_1.out, self.get_previous_component(2).get_carry_wire(), prefix=self.prefix+"_xor"+str(self.get_instance_num(cls=XorGate)))
self.add_component(sign_xor_2)
self.out.connect(self.N, sign_xor_2.out)
self.out.connect(self.N, sign_xor_2.out)

View File

@ -1,19 +1,19 @@
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
from ariths_gen.core import(
from ariths_gen.core import (
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
ConstantWireValue0,
ConstantWireValue1,
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -24,8 +24,23 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate
)
# MULTIPLIERS
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"):
super().__init__()
self.N = max(a.N, b.N)
@ -85,6 +100,21 @@ class UnsignedArrayMultiplier(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"):
super().__init__()
self.c_data_type = "int64_t"

View File

@ -1,20 +1,20 @@
from ariths_gen.multi_bit_circuits.adders.ripple_carry_adder import UnsignedRippleCarryAdder
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
from ariths_gen.core import(
from ariths_gen.core import (
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
ConstantWireValue0,
ConstantWireValue1,
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -25,7 +25,26 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate
)
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):
super().__init__()
self.N = max(a.N, b.N)
@ -103,7 +122,7 @@ class UnsignedDaddaMultiplier(MultiplierCircuit):
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
# Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit)
adder_prefix = unsigned_adder_class_name(a=a , b=b).prefix + str(len(self.columns)-1)
adder_prefix = unsigned_adder_class_name(a=a, b=b).prefix + str(len(self.columns)-1)
adder_a = Bus(prefix=f"{adder_prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = Bus(prefix=f"{adder_prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
@ -114,6 +133,25 @@ class UnsignedDaddaMultiplier(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):
super().__init__()
self.N = max(a.N, b.N)
@ -141,7 +179,7 @@ class SignedDaddaMultiplier(MultiplierCircuit):
self.add_component(constant_wire_1)
# Adding constant wire with value 1 to achieve signedness
# (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end)
# (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end)
self.columns[self.N].insert(1, constant_wire_1.out.get_wire())
self.update_column_heights(curr_column=self.N, curr_height_change=1)
@ -202,7 +240,7 @@ class SignedDaddaMultiplier(MultiplierCircuit):
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
# Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit)
adder_prefix = unsigned_adder_class_name(a=a , b=b).prefix + str(len(self.columns)-1)
adder_prefix = unsigned_adder_class_name(a=a, b=b).prefix + str(len(self.columns)-1)
adder_a = Bus(prefix=f"{adder_prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = Bus(prefix=f"{adder_prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])

View File

@ -1,20 +1,20 @@
from ariths_gen.multi_bit_circuits.adders.ripple_carry_adder import UnsignedRippleCarryAdder
from ariths_gen.wire_components import(
from ariths_gen.wire_components import (
Wire,
Bus
)
from ariths_gen.core import(
from ariths_gen.core import (
ArithmeticCircuit,
MultiplierCircuit
)
from ariths_gen.one_bit_circuits.one_bit_components import(
from ariths_gen.one_bit_circuits.one_bit_components import (
HalfAdder,
ConstantWireValue0,
ConstantWireValue1,
FullAdder,
FullAdderPG
)
from ariths_gen.one_bit_circuits.logic_gates import(
from ariths_gen.one_bit_circuits.logic_gates import (
LogicGate,
AndGate,
NandGate,
@ -25,7 +25,25 @@ from ariths_gen.one_bit_circuits.logic_gates import(
NotGate
)
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):
super().__init__()
self.N = max(a.N, b.N)
@ -98,7 +116,7 @@ class UnsignedWallaceMultiplier(MultiplierCircuit):
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
# Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit)
adder_prefix = unsigned_adder_class_name(a=a , b=b).prefix + str(len(self.columns)-1)
adder_prefix = unsigned_adder_class_name(a=a, b=b).prefix + str(len(self.columns)-1)
adder_a = Bus(prefix=f"{adder_prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = Bus(prefix=f"{adder_prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])
@ -109,6 +127,24 @@ class UnsignedWallaceMultiplier(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):
super().__init__()
self.N = max(a.N, b.N)
@ -134,7 +170,7 @@ class SignedWallaceMultiplier(MultiplierCircuit):
self.add_component(constant_wire_1)
# Adding constant wire with value 1 to achieve signedness
# (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end)
# (adding constant value bit to last column (with one bit) to combine them in XOR gate to get the correct final multplication output bit at the end)
self.columns[self.N].insert(1, constant_wire_1.out.get_wire())
self.update_column_heights(curr_column=self.N, curr_height_change=1)
@ -194,7 +230,7 @@ class SignedWallaceMultiplier(MultiplierCircuit):
# Final addition of remaining bits using chosen unsigned multi bit adder
else:
# Obtain proper adder name with its bit width (columns bit pairs minus the first alone bit)
adder_prefix = unsigned_adder_class_name(a=a , b=b).prefix + str(len(self.columns)-1)
adder_prefix = unsigned_adder_class_name(a=a, b=b).prefix + str(len(self.columns)-1)
adder_a = Bus(prefix=f"{adder_prefix}_a", wires_list=[self.get_column_wire(column=col, bit=1) for col in range(1, len(self.columns))])
adder_b = Bus(prefix=f"{adder_prefix}_b", wires_list=[self.get_column_wire(column=col, bit=2) for col in range(1, len(self.columns))])

View File

@ -1,10 +1,25 @@
from ariths_gen.wire_components import Wire
""" LOGIC GATE COMPONENTS """
# Two-input #
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"):
self.a = Wire(name=prefix+"_"+a.name.replace(prefix+"_", ""), value=a.value)
self.b = Wire(name=prefix+"_"+b.name.replace(prefix+"_", ""), value=b.value)
@ -154,6 +169,23 @@ class 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"):
super().__init__(a, b, prefix)
@ -172,6 +204,24 @@ class InvertedLogicGate(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):
super().__init__(a, b, prefix)
self.gate_type = "and_gate"
@ -186,6 +236,24 @@ class AndGate(LogicGate):
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):
super().__init__(a, b, prefix)
self.gate_type = "nand_gate"
@ -200,6 +268,24 @@ class NandGate(InvertedLogicGate):
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):
super().__init__(a, b, prefix)
self.gate_type = "or_gate"
@ -214,6 +300,24 @@ class OrGate(LogicGate):
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):
super().__init__(a, b, prefix)
self.gate_type = "nor_gate"
@ -228,6 +332,24 @@ class NorGate(InvertedLogicGate):
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):
super().__init__(a, b, prefix)
self.gate_type = "xor_gate"
@ -242,6 +364,24 @@ class XorGate(LogicGate):
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):
super().__init__(a, b, prefix)
self.gate_type = "xnor_gate"
@ -257,6 +397,23 @@ class XnorGate(InvertedLogicGate):
# Single-input #
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):
self.gate_type = "not_gate"
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.wire_components import Wire, Bus
# THREE INPUT CIRCUITS
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"):
super().__init__()
self.c_data_type = "uint8_t"
@ -38,6 +56,24 @@ class FullAdder(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"):
super().__init__()
self.c_data_type = "uint8_t"
@ -61,7 +97,7 @@ class FullAdderPG(ThreeInputOneBitCircuit):
sum_xor = XorGate(propagate_xor.out, c, prefix=self.prefix, outid=2)
self.add_component(sum_xor)
self.out.connect(2, sum_xor.out)
def get_propagate_wire(self):
return self.out.get_wire(0)
@ -69,4 +105,4 @@ class FullAdderPG(ThreeInputOneBitCircuit):
return self.out.get_wire(1)
def get_sum_wire(self):
return self.out.get_wire(2)
return self.out.get_wire(2)

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.wire_components import Wire, Bus
# TWO INPUT CIRCUITS
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"):
super().__init__()
self.c_data_type = "uint8_t"
@ -27,6 +44,23 @@ class HalfAdder(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"):
super().__init__()
self.c_data_type = "uint8_t"
@ -57,7 +91,25 @@ class PGLogicBlock(TwoInputOneBitCircuit):
def get_sum_wire(self):
return self.out.get_wire(2)
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"):
super().__init__()
self.c_data_type = "uint8_t"
@ -83,6 +135,23 @@ class ConstantWireValue0(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"):
super().__init__()
self.c_data_type = "uint8_t"

View File

@ -1,7 +1,17 @@
from .wires import Wire
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:
self.bus = [Wire(name=prefix+"_"+str(i), index=i) for i in range(N)]
self.prefix = prefix
@ -13,45 +23,119 @@ class Bus():
# Connecting output wire of the inner circuit component to the input of another component
# (or to the wire of the circuit's output bus)
def connect(self, out_wire_index: int, inner_component_out_wire: Wire):
self.bus[out_wire_index] = inner_component_out_wire
def connect(self, bus_wire_index: int, inner_component_out_wire: 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):
"""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]
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:
self.bus += [Wire(name=prefix+"_"+str(i), index=i) for i in range(self.N, N)]
self.N = N
""" C CODE GENERATION """
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:
return f" uint64_t {self.prefix} = 0;\n"
else:
return f" uint8_t {self.prefix} = 0;\n"
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])
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
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):
"""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)
""" VERILOG CODE GENERATION """
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])
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
return "".join([w.get_assign_v(name=self.prefix, offset=self.bus.index(w), array=True) for w in self.bus])
""" BLIF CODE GENERATION """
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])
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])

View File

@ -1,4 +1,14 @@
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):
self.name = name
if self.name.endswith("_"+str(index)):
@ -10,23 +20,68 @@ class Wire():
""" C CODE GENERATION """
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"
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
return f"(({w_name} >> {offset}) & 0x01)"
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"
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}"
""" VERILOG CODE GENERATION """
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"
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:
return f" assign {self.name} = {name}[{offset}];\n"
else:
@ -34,15 +89,37 @@ class Wire():
""" BLIF CODE GENERATION """
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:
return f" {name}[{offset}]"
else:
return f" {self.name}"
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:
return f".names {self.name} {name}\n" + \
f"1 1\n"
else:
return f".names {name} {self.name}\n" + \
f"1 1\n"
f"1 1\n"