commit
49cf3150ca
@ -51,9 +51,9 @@ For more detailed description of script's usage, use help.
|
||||
|
||||
## CGP testing
|
||||
The `chr2c.py` script converts the input CGP chromosome generated by ArithsGen to the corresponding C code and prints it to standard output.
|
||||
It is a modified version of a script originally authored by Vojtech Mrazek. Note that it required Python2 to run!
|
||||
It is a modified version of a script originally authored by Vojtech Mrazek.
|
||||
|
||||
### Usage
|
||||
```bash
|
||||
python2 chr2c.py input.chr > output.c
|
||||
python3 chr2c.py input.chr > output.c
|
||||
```
|
||||
|
@ -11,15 +11,14 @@ from ariths_gen.core.arithmetic_circuits.general_circuit import GeneralCircuit
|
||||
|
||||
|
||||
class ArithmeticCircuit(GeneralCircuit):
|
||||
"""Class represents a general arithmetic circuit and ensures their generation to various representations.
|
||||
"""Class represents a general arithmetic circuit and ensures its generation to various representations.
|
||||
|
||||
The __init__ method fills some mandatory attributes concerning arithmetic circuit
|
||||
that are later used for generation into various representations.
|
||||
"""
|
||||
|
||||
def __init__(self, a, b, prefix: str, name: str, out_N: int, inner_component: bool = False, one_bit_circuit: bool = False):
|
||||
|
||||
super().__init__(prefix, name, out_N, inner_component, inputs=[a, b])
|
||||
def __init__(self, a, b, prefix: str, name: str, out_N: int, inner_component: bool = False, one_bit_circuit: bool = False, signed: bool = False):
|
||||
super().__init__(prefix, name, out_N, inner_component, inputs=[a, b], signed=signed)
|
||||
if one_bit_circuit is False:
|
||||
if prefix == "":
|
||||
self.prefix = name
|
||||
@ -40,7 +39,7 @@ class ArithmeticCircuit(GeneralCircuit):
|
||||
self.b = Bus(prefix=f"{b.prefix}", wires_list=b.bus)
|
||||
|
||||
# N output wires for given circuit
|
||||
self.out = Bus(self.prefix+"_out", out_N, out_bus=True)
|
||||
self.out = Bus(self.prefix+"_out", out_N, out_bus=True, signed=self.signed)
|
||||
|
||||
""" C CODE GENERATION """
|
||||
def get_prototype_c(self):
|
||||
@ -51,22 +50,7 @@ class ArithmeticCircuit(GeneralCircuit):
|
||||
"""
|
||||
return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + "\n"
|
||||
|
||||
def get_function_block_c(self):
|
||||
"""Generates hierarchical C code representation of corresponding multi-bit arithmetic circuit used as function block in hierarchical circuit description.
|
||||
|
||||
Returns:
|
||||
str: Hierarchical C code of multi-bit arithmetic circuit's function block description.
|
||||
"""
|
||||
# Obtain proper circuit name with its bit width
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return f"{circuit_block.get_circuit_c()}\n\n"
|
||||
|
||||
""" VERILOG CODE GENERATION """
|
||||
# FLAT VERILOG #
|
||||
|
||||
def get_prototype_v(self):
|
||||
"""Generates Verilog code module header to describe corresponding arithmetic circuit's interface in Verilog code.
|
||||
|
||||
@ -74,50 +58,21 @@ class ArithmeticCircuit(GeneralCircuit):
|
||||
str: Module's name and parameters in Verilog code.
|
||||
"""
|
||||
return f"module {self.prefix}(input [{self.N-1}:0] {self.a.prefix}, input [{self.N-1}:0] {self.b.prefix}, output [{self.out.N-1}:0] {self.out.prefix});\n"
|
||||
# HIERARCHICAL VERILOG #
|
||||
def get_function_block_v(self):
|
||||
"""Generates hierarchical Verilog code representation of corresponding multi-bit arithmetic circuit used as function block in hierarchical circuit description.
|
||||
|
||||
""" BLIF CODE GENERATION """
|
||||
def get_declaration_blif(self):
|
||||
"""Generates flat Blif code declaration of input/output circuit wires.
|
||||
|
||||
Returns:
|
||||
str: Hierarchical Verilog code of multi-bit arithmetic circuit's function block description.
|
||||
str: Flat Blif code containing declaration of circuit's wires.
|
||||
"""
|
||||
# Obtain proper circuit name with its bit width
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return f"{circuit_block.get_circuit_v()}\n\n"
|
||||
def get_out_invocation_v(self, circuit_prefix: str):
|
||||
"""Generates hierarchical Verilog code invocation of corresponding arithmetic circuit's generated function block.
|
||||
|
||||
Assigns input values from other subcomponents into multi-bit input buses used as inputs for function block invocation.
|
||||
Assigns output values from invocation of the corresponding function block into inner wires present inside
|
||||
the upper component from which function block has been invoked.
|
||||
|
||||
Args:
|
||||
circuit_prefix (str): Prefix name of the upper component from which function block is being invoked.
|
||||
|
||||
Returns:
|
||||
str: Hierarchical Verilog code of subcomponent's module invocation and output assignment.
|
||||
"""
|
||||
# Getting name of circuit type and insitu copying out bus for proper Verilog code generation without affecting actual generated composition
|
||||
circuit_type = self.prefix.replace(circuit_prefix+"_", "")
|
||||
|
||||
# Obtain proper circuit name with its bit width
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return self.a.return_bus_wires_values_v_hier() + self.b.return_bus_wires_values_v_hier() + \
|
||||
f" {circuit_type} {circuit_type}_{self.out.prefix}(.{circuit_block.a.prefix}({self.a.prefix}), .{circuit_block.b.prefix}({self.b.prefix}), .{circuit_block.out.prefix}({self.out.prefix}));\n"
|
||||
|
||||
def get_function_block_blif(self):
|
||||
"""Generates hierarchical Blif code representation of corresponding multi-bit arithmetic circuit used as function block in hierarchical circuit description.
|
||||
|
||||
Returns:
|
||||
str: Hierarchical Blif code of multi-bit arithmetic circuit's function block description.
|
||||
"""
|
||||
# Obtain proper circuit name with its bit width
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"))
|
||||
return f"{circuit_block.get_circuit_blif()}"
|
||||
if self.N == 1:
|
||||
return f".inputs {self.a.prefix} {self.b.prefix}\n" + \
|
||||
f".outputs{self.out.get_wire_declaration_blif()}\n" + \
|
||||
f".names vdd\n1\n" + \
|
||||
f".names gnd\n0\n"
|
||||
else:
|
||||
return f".inputs{self.a.get_wire_declaration_blif()}{self.b.get_wire_declaration_blif()}\n" + \
|
||||
f".outputs{self.out.get_wire_declaration_blif()}\n" + \
|
||||
f".names vdd\n1\n" + \
|
||||
f".names gnd\n0\n"
|
||||
|
@ -10,13 +10,13 @@ from ariths_gen.wire_components import (
|
||||
from io import StringIO
|
||||
|
||||
class GeneralCircuit():
|
||||
"""Class represents a general arithmetic circuit and ensures their generation to various representations.
|
||||
"""Class represents a general circuit and ensures its generation to various representations.
|
||||
|
||||
The __init__ method fills some mandatory attributes concerning arithmetic circuit
|
||||
that are later used for generation into various representations.
|
||||
"""
|
||||
|
||||
def __init__(self, prefix: str, name: str, out_N: int, inner_component: bool = False, inputs: list=[]):
|
||||
def __init__(self, prefix: str, name: str, out_N: int, inner_component: bool = False, inputs: list=[], signed: bool = False):
|
||||
if prefix == "":
|
||||
self.prefix = name
|
||||
else:
|
||||
@ -29,6 +29,7 @@ class GeneralCircuit():
|
||||
self.circuit_wires = []
|
||||
self.circuit_gates = []
|
||||
self.c_data_type = "uint64_t"
|
||||
self.signed = signed
|
||||
self.pyc = None # Python compiled function
|
||||
|
||||
def __call__(self, *args):
|
||||
@ -242,30 +243,30 @@ class GeneralCircuit():
|
||||
""" PYTHON CODE GENERATION """
|
||||
# FLAT PYTHON #
|
||||
def get_prototype_python(self):
|
||||
"""Generates python code function header to describe corresponding arithmetic circuit's interface in python code.
|
||||
"""Generates Python code function header to describe corresponding arithmetic circuit's interface in Python code.
|
||||
|
||||
Returns:
|
||||
str: Function's name and parameters in C code.
|
||||
str: Function's name and parameters in Python code.
|
||||
"""
|
||||
return f"def {self.prefix}(" + ", ".join([f"{x.prefix}" for x in self.inputs]) + ")" + ":" + "\n"
|
||||
|
||||
def get_init_python_flat(self):
|
||||
"""Generates flat C code initialization and assignment of corresponding arithmetic circuit's input/output wires.
|
||||
"""Generates flat Python code initialization and assignment of corresponding arithmetic circuit's input/output wires.
|
||||
|
||||
Returns:
|
||||
str: Flat C code initialization of arithmetic circuit wires.
|
||||
str: Flat Python code initialization of arithmetic circuit wires.
|
||||
"""
|
||||
return "".join([c.get_assign_python_flat() if isinstance(c, TwoInputLogicGate) else c.get_init_python_flat() for c in self.components])
|
||||
|
||||
def get_function_out_python_flat(self):
|
||||
"""Generates flat C code assignment of corresponding arithmetic circuit's output bus wires.
|
||||
"""Generates flat Python code assignment of corresponding arithmetic circuit's output bus wires.
|
||||
|
||||
Returns:
|
||||
str: Flat C code containing output bus wires assignment.
|
||||
str: Flat Python code containing output bus wires assignment.
|
||||
"""
|
||||
return self.out.return_bus_wires_values_python_flat()
|
||||
|
||||
# Generating flat C code representation of circuit
|
||||
# Generating flat Python code representation of circuit
|
||||
def get_python_code_flat(self, file_object):
|
||||
"""Generates flat Python code representation of corresponding arithmetic circuit.
|
||||
|
||||
@ -277,6 +278,7 @@ class GeneralCircuit():
|
||||
#file_object.write(self.get_declaration_python_flat()+"\n")
|
||||
file_object.write(self.get_init_python_flat()+"\n")
|
||||
file_object.write(self.get_function_out_python_flat())
|
||||
file_object.write(self.out.return_bus_wires_sign_extend_python())
|
||||
file_object.write(f" return {self.out.prefix}"+"\n")
|
||||
|
||||
""" C CODE GENERATION """
|
||||
@ -335,6 +337,7 @@ class GeneralCircuit():
|
||||
file_object.write(self.get_declaration_c_flat()+"\n")
|
||||
file_object.write(self.get_init_c_flat()+"\n")
|
||||
file_object.write(self.get_function_out_c_flat())
|
||||
file_object.write(self.out.return_bus_wires_sign_extend_c())
|
||||
file_object.write(f" return {self.out.prefix}"+";\n}")
|
||||
|
||||
# HIERARCHICAL C #
|
||||
@ -358,7 +361,7 @@ class GeneralCircuit():
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), prefix=circuit_prefix)
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return f"{circuit_block.get_circuit_c()}\n\n"
|
||||
|
||||
def get_declarations_c_hier(self):
|
||||
@ -427,6 +430,7 @@ class GeneralCircuit():
|
||||
f"{self.get_declarations_c_hier()}\n" + \
|
||||
f"{self.get_init_c_hier()}\n" + \
|
||||
f"{self.get_function_out_c_hier()}" + \
|
||||
f"{self.out.return_bus_wires_sign_extend_c()}" + \
|
||||
f" return {self.out.prefix}"+";\n}"
|
||||
|
||||
# Generating hierarchical C code representation of circuit
|
||||
@ -509,7 +513,7 @@ class GeneralCircuit():
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), prefix=circuit_prefix)
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return f"{circuit_block.get_circuit_v()}\n\n"
|
||||
|
||||
def get_declarations_v_hier(self):
|
||||
@ -561,7 +565,7 @@ class GeneralCircuit():
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), prefix=circuit_prefix)
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return self.a.return_bus_wires_values_v_hier() + self.b.return_bus_wires_values_v_hier() + \
|
||||
f" {circuit_type} {circuit_type}_{self.out.prefix}(.{circuit_block.a.prefix}({self.a.prefix}), .{circuit_block.b.prefix}({self.b.prefix}), .{circuit_block.out.prefix}({self.out.prefix}));\n"
|
||||
|
||||
@ -612,16 +616,10 @@ class GeneralCircuit():
|
||||
Returns:
|
||||
str: Flat Blif code containing declaration of circuit's wires.
|
||||
"""
|
||||
if self.N == 1:
|
||||
return f".inputs {self.a.prefix} {self.b.prefix}\n" + \
|
||||
f".outputs{self.out.get_wire_declaration_blif()}\n" + \
|
||||
f".names vdd\n1\n" + \
|
||||
f".names gnd\n0\n"
|
||||
else:
|
||||
return f".inputs{self.a.get_wire_declaration_blif()}{self.b.get_wire_declaration_blif()}\n" + \
|
||||
f".outputs{self.out.get_wire_declaration_blif()}\n" + \
|
||||
f".names vdd\n1\n" + \
|
||||
f".names gnd\n0\n"
|
||||
return f".inputs{''.join([w.get_wire_declaration_blif() for w in self.inputs])}\n" + \
|
||||
f".outputs{self.out.get_wire_declaration_blif()}\n" + \
|
||||
f".names vdd\n1\n" + \
|
||||
f".names gnd\n0\n"
|
||||
|
||||
def get_function_blif_flat(self):
|
||||
"""Generates flat Blif code with invocation of subcomponents logic gates functions via their corresponding truth tables.
|
||||
@ -715,7 +713,7 @@ class GeneralCircuit():
|
||||
circuit_prefix = self.__class__(
|
||||
a=Bus("a"), b=Bus("b")).prefix + str(self.N)
|
||||
circuit_block = self.__class__(a=Bus(N=self.N, prefix="a"), b=Bus(
|
||||
N=self.N, prefix="b"), prefix=circuit_prefix)
|
||||
N=self.N, prefix="b"), name=circuit_prefix)
|
||||
return f"{circuit_block.get_circuit_blif()}"
|
||||
|
||||
# Generating hierarchical BLIF code representation of circuit
|
||||
|
@ -195,11 +195,13 @@ class TwoInputLogicGate():
|
||||
else:
|
||||
return f" {self.out.name} = {self.gate_type}({self.a.get_wire_value_c_hier()}, {self.b.get_wire_value_c_hier()});\n"
|
||||
|
||||
""" PYTHON CODE GENERATION """
|
||||
# FLAT PYTHON #
|
||||
def get_assign_python_flat(self):
|
||||
"""Generates C code for invocation of logical functions and subsequently provides assignment to their output.
|
||||
"""Generates Python code for invocation of logical functions and subsequently provides assignment to their output.
|
||||
|
||||
Returns:
|
||||
str: C code invocation of logical function and assignment to output.
|
||||
str: Python code invocation of logical function and assignment to output.
|
||||
"""
|
||||
# No gate logic is generated if one of the inputs is a wire with constant value.
|
||||
# I.e. either the constant or the second input wire is propagated to the output for the corresponding logic gate's logic function.
|
||||
|
@ -184,7 +184,7 @@ class SignedCarryLookaheadAdder(UnsignedCarryLookaheadAdder, ArithmeticCircuit):
|
||||
name (str, optional): Name of signed cla. Defaults to "s_cla".
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, cla_block_size: int = 4, prefix: str = "", name: str = "s_cla", **kwargs):
|
||||
super().__init__(a=a, b=b, cla_block_size=cla_block_size, prefix=prefix, name=name, **kwargs)
|
||||
super().__init__(a=a, b=b, cla_block_size=cla_block_size, prefix=prefix, name=name, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Additional XOR gates to ensure correct sign extension in case of sign addition
|
||||
|
@ -167,7 +167,7 @@ class SignedCarrySkipAdder(UnsignedCarrySkipAdder, ArithmeticCircuit):
|
||||
name (str, optional): Name of signed cska. Defaults to "s_cska".
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, bypass_block_size: int = 4, prefix: str = "", name: str = "s_cska", **kwargs):
|
||||
super().__init__(a=a, b=b, bypass_block_size=bypass_block_size, prefix=prefix, name=name, **kwargs)
|
||||
super().__init__(a=a, b=b, bypass_block_size=bypass_block_size, prefix=prefix, name=name, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Additional XOR gates to ensure correct sign extension in case of sign addition
|
||||
|
@ -130,7 +130,7 @@ class SignedPGRippleCarryAdder(UnsignedPGRippleCarryAdder, ArithmeticCircuit):
|
||||
name (str, optional): Name of signed P/G rca. Defaults to "s_pg_rca".
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, prefix: str = "", name: str = "s_pg_rca", **kwargs):
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, **kwargs)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Additional XOR gates to ensure correct sign extension in case of sign addition
|
||||
|
@ -106,7 +106,7 @@ class SignedRippleCarryAdder(UnsignedRippleCarryAdder, ArithmeticCircuit):
|
||||
name (str, optional): Name of signed rca. Defaults to "s_rca".
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, prefix: str = "", name: str = "s_rca", **kwargs):
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, **kwargs)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Additional XOR gates to ensure correct sign extension in case of sign addition
|
||||
|
@ -191,7 +191,7 @@ class SignedArrayMultiplier(MultiplierCircuit):
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, prefix: str = "", name: str = "s_arrmul", **kwargs):
|
||||
self.N = max(a.N, b.N)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, out_N=self.N*2, **kwargs)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, out_N=self.N*2, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Bus sign extension in case buses have different lengths
|
||||
|
@ -155,7 +155,7 @@ class SignedDaddaMultiplier(MultiplierCircuit):
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, prefix: str = "", name: str = "s_dadda_cla", unsigned_adder_class_name: str = UnsignedCarryLookaheadAdder, **kwargs):
|
||||
self.N = max(a.N, b.N)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, out_N=self.N*2, **kwargs)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, out_N=self.N*2, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Bus sign extension in case buses have different lengths
|
||||
|
@ -148,7 +148,7 @@ class SignedWallaceMultiplier(MultiplierCircuit):
|
||||
"""
|
||||
def __init__(self, a: Bus, b: Bus, prefix: str = "", name: str = "s_wallace_cla", unsigned_adder_class_name: str = UnsignedCarryLookaheadAdder, **kwargs):
|
||||
self.N = max(a.N, b.N)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, out_N=self.N*2, **kwargs)
|
||||
super().__init__(a=a, b=b, prefix=prefix, name=name, out_N=self.N*2, signed=True, **kwargs)
|
||||
self.c_data_type = "int64_t"
|
||||
|
||||
# Bus sign extension in case buses have different lengths
|
||||
|
@ -11,8 +11,9 @@ class 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.
|
||||
out_bus (bool, optional): Specifies whether this Bus is an output bus of some previous component. Defaults to False.
|
||||
signed (bool, optional): Specifies whether this Bus should consider signed numbers or not (used for C code generation). Defaults to False.
|
||||
"""
|
||||
def __init__(self, prefix: str = "bus", N: int = 1, wires_list: list = None, out_bus: bool = False):
|
||||
def __init__(self, prefix: str = "bus", N: int = 1, wires_list: list = None, out_bus: bool = False, signed: bool = False):
|
||||
self.out_bus = out_bus
|
||||
if wires_list is None:
|
||||
self.prefix = prefix
|
||||
@ -23,6 +24,21 @@ class Bus():
|
||||
self.prefix = prefix
|
||||
self.bus = wires_list
|
||||
self.N = len(self.bus)
|
||||
|
||||
# Determine C code signedness
|
||||
self.signed = signed
|
||||
if self.N > 8:
|
||||
self.c_var_size = 64
|
||||
if signed is True:
|
||||
self.c_type = "int64_t"
|
||||
else:
|
||||
self.c_type = "uint64_t"
|
||||
else:
|
||||
self.c_var_size = 8
|
||||
if signed is True:
|
||||
self.c_type = "int8_t"
|
||||
else:
|
||||
self.c_type = "uint8_t"
|
||||
|
||||
def is_output_bus(self):
|
||||
"""Tells whether this Bus is an output bus.
|
||||
@ -79,21 +95,42 @@ class Bus():
|
||||
elif inserted_wire_desired_index != -1:
|
||||
self.bus[bus_wire_index] = Wire(name=inner_component_out_wire.name, prefix=inner_component_out_wire.parent_bus.prefix, index=inserted_wire_index, value=inner_component_out_wire.value, parent_bus=self)
|
||||
|
||||
# TODO
|
||||
def connect_bus(self, connecting_bus, start_connection_pos: int = 0, end_connection_pos: int = -1):
|
||||
def connect_bus(self, connecting_bus: object, start_connection_pos: int = 0, end_connection_pos: int = -1):
|
||||
"""Ensures connection of specified bus wires to this bus wires.
|
||||
|
||||
Used for connection of some inner circuit component's output bus (`connecting_bus`) wires
|
||||
to the appropriate input bus (this `self` bus) wires of some other circuit.
|
||||
|
||||
Args:
|
||||
connecting_bus (object): Specifies the connecting bus.
|
||||
start_connection_pos (int, optional): Specifies the position from which to start interconnecting wires from the `connecting_bus` to this `self` bus. Defaults to 0.
|
||||
end_connection_pos (int, optional): Specifies the position from which to end interconnecting wires from the `connecting_bus` to this `self` bus. Defaults to -1.
|
||||
"""
|
||||
if end_connection_pos == -1:
|
||||
end_connection_pos = self.N
|
||||
|
||||
# Nakonec je potřeba napojit výstup adderu na výstup mac
|
||||
|
||||
[self.connect(o, connecting_bus.get_wire(o), inserted_wire_desired_index=o) for o in range(start_connection_pos, end_connection_pos)]
|
||||
|
||||
""" PYTHON CODE GENERATION """
|
||||
def return_bus_wires_values_python_flat(self):
|
||||
"""Retrieves values from bus's wires and stores them in bus's corresponding C variable at proper offset bit position in the bus for flat generation.
|
||||
"""Retrieves values from bus's wires and stores them in bus's corresponding Python variable (object) at proper offset bit position in the bus for flat generation.
|
||||
|
||||
Returns:
|
||||
str: C code for assigning wire values into bus represented in C code variable.
|
||||
str: Python code for assigning wire values into bus represented in Python code variable.
|
||||
"""
|
||||
return "".join([f" {self.prefix} = 0\n"] + [f" {self.prefix} |= {w.return_wire_value_python_flat(offset=self.bus.index(w))}" for w in self.bus])
|
||||
|
||||
def return_bus_wires_sign_extend_python(self):
|
||||
"""Sign extends the bus's corresponding Python variable (object) to ensure proper Python code variable signedness.
|
||||
|
||||
Returns:
|
||||
str: Python code for sign extending the bus variable wire values.
|
||||
"""
|
||||
if self.signed is True:
|
||||
last_bus_wire = self.bus[-1]
|
||||
return "".join([f" {self.prefix} |= {last_bus_wire.return_wire_value_python_flat(offset=i)}" for i in range(len(self.bus), 64)])
|
||||
else:
|
||||
return ""
|
||||
|
||||
""" C CODE GENERATION """
|
||||
def get_declaration_c(self):
|
||||
@ -102,10 +139,8 @@ class Bus():
|
||||
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"
|
||||
return f" {self.c_type} {self.prefix} = 0;\n"
|
||||
|
||||
|
||||
def return_bus_wires_values_c_flat(self):
|
||||
"""Retrieves values from bus's wires and stores them in bus's corresponding C variable at proper offset bit position in the bus for flat generation.
|
||||
@ -123,6 +158,18 @@ class Bus():
|
||||
"""
|
||||
return "".join([f" {self.prefix} |= {w.return_wire_value_c_hier(offset=self.bus.index(w))}" for w in self.bus])
|
||||
|
||||
def return_bus_wires_sign_extend_c(self):
|
||||
"""Sign extends the bus's corresponding C variable to ensure proper C code variable signedness.
|
||||
|
||||
Returns:
|
||||
str: C code for sign extending the bus variable wire values.
|
||||
"""
|
||||
if self.signed is True:
|
||||
last_bus_wire = self.bus[-1]
|
||||
return "".join([f" {self.prefix} |= {last_bus_wire.return_wire_value_c_flat(offset=i)}" for i in range(len(self.bus), self.c_var_size)])
|
||||
else:
|
||||
return ""
|
||||
|
||||
""" VERILOG CODE GENERATION """
|
||||
def return_bus_wires_values_v_flat(self):
|
||||
"""Retrieves values from bus's wires and stores them in bus's corresponding Verilog variable at proper offset bit position in the bus for flat generation.
|
||||
|
@ -26,15 +26,15 @@ class Wire():
|
||||
"""
|
||||
return False
|
||||
|
||||
""" Python CODE GENERATION """
|
||||
""" PYTHON CODE GENERATION """
|
||||
def return_wire_value_python_flat(self, offset: int = 0):
|
||||
"""Retrieves desired bit value from wire represented in C code variable and bitwise shifts it to desired position for storing it within a bus for flat generation.
|
||||
"""Retrieves desired bit value from wire represented in Python code variable (object) and bitwise shifts it to desired position for storing it within a bus for flat generation.
|
||||
|
||||
Args:
|
||||
offset (int, optional): Used to shift wire value in order to be stored in proper location inside a bus. Defaults to 0.
|
||||
|
||||
Returns:
|
||||
str: C code bitwise shift for storing (constant/variable) wire value at desired offset position.
|
||||
str: Python code bitwise shift for storing (constant/variable) wire value at desired offset position.
|
||||
"""
|
||||
if self.is_const():
|
||||
return f"({self.c_const}) << {offset}\n"
|
||||
@ -92,7 +92,7 @@ class Wire():
|
||||
if self.is_const():
|
||||
return f"({self.c_const}) << {offset};\n"
|
||||
else:
|
||||
return f"(({self.name} >> 0) & 0x01) << {offset};\n"
|
||||
return f"(({self.name} >> 0) & 0x01ull) << {offset};\n"
|
||||
|
||||
def return_wire_value_c_hier(self, offset: int = 0):
|
||||
"""Retrieves desired bit value from wire represented in C code variable and bitwise shifts it to desired position for storing it within a bus for hierarchical generation.
|
||||
@ -106,7 +106,7 @@ class Wire():
|
||||
if self.is_const():
|
||||
return f"({self.c_const}) << {offset};\n"
|
||||
else:
|
||||
return f"(({self.prefix} >> {self.index}) & 0x01) << {offset};\n"
|
||||
return f"(({self.prefix} >> {self.index}) & 0x01ull) << {offset};\n"
|
||||
|
||||
""" VERILOG CODE GENERATION """
|
||||
def get_declaration_v_flat(self):
|
||||
|
10
chr2c.py
10
chr2c.py
@ -86,7 +86,7 @@ def parse_chromosome(chromosome, signed=False, function=None):
|
||||
output.append(f"{dtype} {function}({dtype} a, {dtype} b) {{")
|
||||
output.append(" int wa[%d];" % int(c_in/2))
|
||||
output.append(" int wb[%d];" % int(c_in/2))
|
||||
output.append(" uint64_t y = 0;")
|
||||
output.append(f" {dtype} y = 0;")
|
||||
|
||||
# Export converted input assignments into C code function body
|
||||
trans = {}
|
||||
@ -126,10 +126,16 @@ def parse_chromosome(chromosome, signed=False, function=None):
|
||||
# Export converted outputs into C code function body
|
||||
for i in range(0, c_out):
|
||||
if outs[i] in trans:
|
||||
lines_end.append(" y |= (%s & 0x01) << %d; // default output" % (trans[outs[i]], i))
|
||||
lines_end.append(" y |= (%s & 0x01ull) << %d; // default output" % (trans[outs[i]], i))
|
||||
else:
|
||||
assert False
|
||||
|
||||
# Ensure proper sign extension if it is needed
|
||||
if signed is True:
|
||||
last_out_wire = trans[outs[-1]] # used for sign extension
|
||||
for i in range(c_out, 64):
|
||||
lines_end.append(" y |= (%s & 0x01ull) << %d; // default output" % (last_out_wire, i))
|
||||
|
||||
# Print final result return in C code function body and close it
|
||||
lines_end.append(" return y;")
|
||||
output += lines
|
||||
|
@ -10,11 +10,6 @@ int main() {
|
||||
for (int i = -128; i < 128; i++){
|
||||
for (int j = -128; j < 128; j++){
|
||||
result = i + j;
|
||||
|
||||
// Calculating 2's complement in case of negative sum
|
||||
if (result < 0) {
|
||||
result = 512 + result;
|
||||
}
|
||||
|
||||
assert(result == (int)CNAME(i,j));
|
||||
}
|
||||
|
@ -10,11 +10,6 @@ int main() {
|
||||
for (int i = -128; i < 128; i++){
|
||||
for (int j = -128; j < 128; j++){
|
||||
result = i * j;
|
||||
|
||||
// Calculating 2's complement in case of negative sum
|
||||
if (result < 0) {
|
||||
result = 65536 + result;
|
||||
}
|
||||
|
||||
assert(result == (int)CNAME(i,j));
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ def test_signed_mul():
|
||||
mul = c(a, b)
|
||||
r = mul(av, bv)
|
||||
|
||||
r[r >= 2**(2*N-1)] -= 2**(2*N) # hack!!! two's complement not implemented yet
|
||||
# r[r >= 2**(2*N-1)] -= 2**(2*N) # hack!!! two's complement not implemented yet
|
||||
np.testing.assert_array_equal(expected, r)
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ def test_signed_add():
|
||||
for c in [SignedCarryLookaheadAdder, SignedPGRippleCarryAdder, SignedRippleCarryAdder, SignedCarrySkipAdder]:
|
||||
mul = c(a, b)
|
||||
r = mul(av, bv)
|
||||
r[r >= 2**(N)] -= 2**(N+1) # hack!!! two's complement not implemented yet
|
||||
# r[r >= 2**(N)] -= 2**(N+1) # hack!!! two's complement not implemented yet
|
||||
np.testing.assert_array_equal(expected, r)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user