def test_pyha_to_python_value(self): class A(Hardware): def __init__(self): self.f = Sfix(0.5, 0, -5) self.fl = [Sfix(0.5, 0, -5)] * 2 a = VHDLModule('name', A(), A()) pyt = a._pyha_to_python_value() assert pyt.f == 0.5 assert pyt.fl == [0.5] * 2
def __init__(self, red_node, parent=None): super().__init__(red_node, parent) # todo: remove me after refactorings try: self.data = VHDLModule('-', convert_obj) except AttributeError: self.data = None # collect multiline comment self.multiline_comment = '' if len(self.value) and isinstance(self.value[0], StringNodeVHDL): self.multiline_comment = str(self.value[0]) del self.value[0]
def test_pyha_is_equal(self): class A(Hardware): def __init__(self, v): self.f = v a = VHDLModule('name', A(False), A(True)) b = VHDLModule('name', A(True), A(False)) assert a._pyha_is_equal(a) assert not a._pyha_is_equal(b) a = VHDLModule('name', A([1, 2, 3]), A([1, 2, 3])) b = VHDLModule('name', A([3, 2, 1]), A([3, 2, 1])) assert a._pyha_is_equal(a) assert not a._pyha_is_equal(b)
def setup(self): class T(Hardware): def __init__(self): self.a = 0 self.b = Sfix(0, 0, -17) self.dut = VHDLModule('name', T(), T())
def test_pyha_convert_from_stdlogic(self): class B(Hardware): def __init__(self): self.f = Sfix(0, 0, -17) class A(Hardware): def __init__(self): self.i = 1 self.b = False self.sub = B() a = VHDLModule('name', A(), A()) expect = 'var.i := to_integer(signed(in0(31 downto 0)));\n' \ 'var.b := logic_to_bool(in0(32 downto 32));\n' \ 'var.sub.f := Sfix(in0(50 downto 33), 0, -17);\n' assert expect == a._pyha_convert_from_stdlogic('var', 'in0')
def test_pyha_convert_to_stdlogic(self): class B(Hardware): def __init__(self): self.f = Sfix(0, 0, -17) class A(Hardware): def __init__(self): self.i = 1 self.b = False self.sub = B() a = VHDLModule('name', A(), A()) expect = 'var(31 downto 0) <= std_logic_vector(to_signed(in0.i, 32));\n' \ 'var(32 downto 32) <= bool_to_logic(in0.b);\n' \ 'var(50 downto 33) <= to_slv(in0.sub.f);\n' assert expect == a._pyha_convert_to_stdlogic('var', 'in0')
def transform_enum(red_node): """ Converts 'EnumType.ENUMVALUE' to integer value , see #154 """ data = VHDLModule('-', convert_obj) enums = [x for x in data.elems if isinstance(x, VHDLEnum)] for x in enums: type_name = x._pyha_type() red_names = red_node.find_all('atomtrailers', value=lambda x: x[0].value == type_name) for i, node in enumerate(red_names): enum_obj = type(x.current)[str(node[1])] red_names[i].replace(str(enum_obj.value))
def transform_dynamic_lists(red_node): data = VHDLModule('-', convert_obj) dynamic_lists = [ x for x in data.elems if isinstance(x, VHDLList) and not x.elements_compatible_typed ] for x in dynamic_lists: name = x._name red_names = red_node.find_all('atomtrailers') for node in red_names: for i, part in enumerate(node): if str(part) == name and isinstance(part.next, GetitemNode): try: index = int(str(part.next.value)) part.replace(f'{name}_{index}') del node[i + 1] except ValueError: line_node = node while True: if type(line_node.next) == EndlNode: break if hasattr(line_node.parent, 'value') and type( line_node.parent.value) == LineProxyList: if not ( hasattr(line_node.parent, 'test') and (line_node.parent.test == node # if WE are the if condition, skip or line_node.parent.test == node.parent) ): # if WE are the if condition (part of condition) break line_node = line_node.parent index = str(part.next.value) node[i + 1].replace( ' ') # del node[i+1], crashes redbaron correct_indentation = line_node.indentation new = 'if True:\n' # replace needs a BLOCK, so this is a dummy IF for i in range(len(x.elems)): part.replace(f'{name}_{i}') head = 'if' if i == 0 else 'elif' new += f'{correct_indentation}\t{head} {index} == {i}:\n{correct_indentation}\t\t{line_node}\n' line_node.replace(new)
def __init__(self, simulated_object): self.simulated_object = simulated_object self.simulated_object_vhdl = VHDLModule('-', self.simulated_object) # 0 or 1 calls wont propagate register outputs if self.simulated_object.main.calls == 0: raise NotTrainedError( 'Top level object must be trained (executed) > 1 times.') if len(self.get_object_inputs()) == 0: raise NoInputsError( 'Top level "main" has no inputs (arguments to main).') if len(self.get_object_return()) == 0: raise NoOutputsError( 'Top level "main" has no outputs (return values).')
def test_pyha_type_is_compatible(self): class A(Hardware): def __init__(self, init): self.REG = init class B(Hardware): def __init__(self): self.REG = 1 self.lol = False class C(Hardware): def __init__(self): self.a = A(1) self.b = B() a = VHDLModule('name', A(1), A(2)) b = VHDLModule('name', B(), B()) c = VHDLModule('name', C(), C()) assert a._pyha_type_is_compatible(a) assert not a._pyha_type_is_compatible(b) assert c._pyha_type_is_compatible(c) assert not c._pyha_type_is_compatible(a) assert not c._pyha_type_is_compatible(b)
def __init__(self, obj, datamodel=None): """ Convert object and all childs to VHDL """ with RecursiveConverter.in_progress: self.obj = obj self.class_name = obj.__class__.__name__ self.datamodel = datamodel self.is_root = datamodel is None if self.is_root: RecursiveConverter.converted_modules = {} RecursiveConverter.typedefs = [] self.datamodel = VHDLModule('-', obj) # recursively convert all child modules self.childs = [] def conv(self, node): if isinstance(node, VHDLList): if node.elements_compatible_typed: if isinstance(node.elems[0], VHDLModule): if self.is_compatible_with_converted_module( node.elems[0]): return self.childs.append( RecursiveConverter(node.elems[0].current, node.elems[0])) else: # dynamic list..need to convert all modules for x in node.elems: if isinstance(x, VHDLModule): if self.is_compatible_with_converted_module(x): return self.childs.append( RecursiveConverter(x.current, x)) elif isinstance(node, VHDLModule): if self.is_compatible_with_converted_module(node): return self.childs.append(RecursiveConverter(node.current, node)) if self.is_root: logger.info(f'Creating top.vhd ...') self.top_vhdl = TopGenerator(obj) # maybe some input/output is a convertible module? for node in self.inputs: conv(self, node) for node in self.outputs: conv(self, node) # iterate all functions and discover local variables that may need to be converted for x in self.obj.__dict__.values(): if isinstance(x, PyhaFunc): for key, val in x.get_local_types().items(): if isinstance(val, Hardware): node = init_vhdl_type(key, val) conv(self, node) # convert instance elements before the instance itself, recursive for node in self.datamodel.elems: conv(self, node) self.red_node = get_objects_rednode(obj) logger.info(f'{self.class_name} to VHDL ...') self.conv = convert(self.red_node, obj) # actual conversion happens here self.vhdl_conversion = str(self.conv) RecursiveConverter.converted_modules[ self.get_module_converted_name( self.datamodel)] = (self.datamodel, self.vhdl_conversion) RecursiveConverter.typedefs.extend(self.conv.build_typedefs())
class ClassNodeVHDL(NodeVHDL): def __init__(self, red_node, parent=None): super().__init__(red_node, parent) # todo: remove me after refactorings try: self.data = VHDLModule('-', convert_obj) except AttributeError: self.data = None # collect multiline comment self.multiline_comment = '' if len(self.value) and isinstance(self.value[0], StringNodeVHDL): self.multiline_comment = str(self.value[0]) del self.value[0] def get_function(self, name): f = [x for x in self.value if str(x.name) == name] assert len(f) return f[0] def build_imports(self): template = textwrap.dedent("""\ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.fixed_float_types.all; use ieee.fixed_pkg.all; use ieee.math_real.all; library work; use work.complex_pkg.all; use work.PyhaUtil.all; use work.Typedefs.all; use work.all; {IMPORTS}""") # add all converted classes to imports # look: https://github.com/tgingold/ghdl/issues/209 from pyha.conversion.conversion import RecursiveConverter imports = [ f'use work.{x}.all;' for x in RecursiveConverter.converted_modules.keys() ] return template.format(IMPORTS=formatter(imports)) def build_constructor(self, prototype_only=False): template = textwrap.dedent("""\ function {NAME}{ARGS} return self_t is -- constructor variable self: self_t; begin {DATA} return self; end function;""") data = [x._pyha_constructor() for x in self.data.elems] args = '; '.join([ x._pyha_constructor_arg() for x in self.data.elems if x._pyha_constructor_arg() != '' ]) if args != '': args = f'({args[:-2]})' if args[-2:] == '; ' else f'({args})' ret = template.format(NAME=escape_reserved_vhdl(self.name), ARGS=args, DATA=formatter(data)) if prototype_only: return ret.splitlines()[0][:-3] + ';' return ret def build_data_structs(self): template = textwrap.dedent("""\ type self_t is record {DATA} end record;""") data = [ x._pyha_definition() for x in self.data.elems if not is_constant(x._name) ] if not data: data = ['dummy: integer;'] return template.format(DATA=formatter(data)) def build_constants(self): template = textwrap.dedent("""\ type self_t_const is record {DATA} end record;""") data = [ x._pyha_definition() for x in self.data.elems if const_filter(x) ] if not data: data = ['DUMMY: integer;'] return template.format(DATA=formatter(data)) def build_typedefs(self): # self typedefs typedefs = [ x._pyha_typedef() for x in self.data.elems if x._pyha_typedef() is not None ] # local vars for function in self.value: if not isinstance(function, DefNodeVHDL): continue variables = [ init_vhdl_type(name, val, val) for name, val in function.data.get_local_types().items() ] typedefs += [ x._pyha_typedef() for x in variables if x is not None and x._pyha_typedef() is not None ] typedefs = list(dict.fromkeys(typedefs)) # get rid of duplicates return typedefs def build_package_header(self): template = textwrap.dedent("""\ {MULTILINE_COMMENT} package {NAME} is {SELF_T} {SELF_ARRAY_TYPEDEF} {CONST_SELF_T} {CONST_SELF_ARRAY_TYPEDEF} {FUNC_HEADERS} end package;""") sockets = {} sockets['MULTILINE_COMMENT'] = self.multiline_comment sockets['NAME'] = self.data._pyha_module_name() # data-structure without constants ie. registers sockets['SELF_T'] = tabber(self.build_data_structs()) sockets[ 'SELF_ARRAY_TYPEDEF'] = f' type {self.data._pyha_arr_type_name()} is array (natural range <>) of {self.data._pyha_type()};' # only constants with TypeAppendHack('_const'): sockets['CONST_SELF_T'] = tabber(self.build_constants()) sockets[ 'CONST_SELF_ARRAY_TYPEDEF'] = f' type {self.data._pyha_arr_type_name()} is array (natural range <>) of {self.data._pyha_type()};' proto = '\n'.join( x.build_function(prototype_only=True) for x in self.value if isinstance(x, DefNodeVHDL)) proto += '\n' + self.build_constructor(prototype_only=True) + '\n' sockets['FUNC_HEADERS'] = tabber(proto) return template.format(**sockets) def build_package_body(self): template = textwrap.dedent("""\ package body {NAME} is {USER_FUNCTIONS} {CONSTRUCTOR} end package body;""") sockets = {} sockets['NAME'] = self.data._pyha_module_name() sockets['CONSTRUCTOR'] = tabber(self.build_constructor()) # sockets['INIT_SELF'] = tabber(self.build_init()) # sockets['CONSTANT_SELF'] = tabber(self.build_reset_constants()) # sockets['RESET_SELF'] = tabber(self.build_reset()) # sockets['UPDATE_SELF'] = tabber(self.build_update_registers()) sockets['USER_FUNCTIONS'] = '\n\n'.join( tabber(str(x)) for x in self.value if isinstance(x, DefNodeVHDL)) return template.format(**sockets) def __str__(self): template = textwrap.dedent("""\ {FILE_HEADER} {IMPORTS} {PACKAGE_HEADER} {PACKAGE_BODY} """) sockets = {} sockets['FILE_HEADER'] = file_header() sockets['IMPORTS'] = self.build_imports() sockets['PACKAGE_HEADER'] = self.build_package_header() sockets['PACKAGE_BODY'] = self.build_package_body() return template.format(**sockets)
def object_class_name(self) -> str: # make sure we escape reserved names mod = VHDLModule('-', self.simulated_object) return mod._pyha_module_name()