def _instantiate_children_tasks( self, task: Task, width_table: Dict[str, int], ) -> List[ast.Identifier]: is_done_signals: List[rtl.Pipeline] = [] arg_table: Dict[str, rtl.Pipeline] = {} async_mmap_args: Dict[Instance.Arg, List[str]] = collections.OrderedDict() task.add_m_axi(width_table, self.tcl_files) for instance in task.instances: child_port_set = set(instance.task.module.ports) # add signal delcarations for arg in instance.args: if arg.cat not in { Instance.Arg.Cat.ISTREAM, Instance.Arg.Cat.OSTREAM, }: width = 64 # 64-bit address if arg.cat == Instance.Arg.Cat.SCALAR: width = width_table.get(arg.name, 0) if width == 0: width = int(arg.name.split("'d")[0]) q = rtl.Pipeline( name=instance.get_instance_arg(arg.name), level=self.register_level, width=width, ) arg_table[arg.name] = q task.module.add_pipeline(q, init=ast.Identifier(arg.name)) # arg.name is the upper-level name # arg.port is the lower-level name # check which ports are used for async_mmap if arg.cat == Instance.Arg.Cat.ASYNC_MMAP: for tag in rtl.ASYNC_MMAP_SUFFIXES: if set(x.portname for x in rtl.generate_async_mmap_ports( tag=tag, port=arg.port, arg=arg.name, instance=instance, )) & child_port_set: async_mmap_args.setdefault(arg, []).append(tag) # declare wires or forward async_mmap ports for tag in async_mmap_args.get(arg, []): if task.is_upper and instance.task.is_lower: task.module.add_signals( rtl.generate_async_mmap_signals( tag=tag, arg=arg.mmap_name, data_width=width_table[arg.name], )) else: task.module.add_ports( rtl.generate_async_mmap_ioports( tag=tag, arg=arg.name, data_width=width_table[arg.name], )) # add reset registers rst_q = rtl.Pipeline(instance.rst_n, level=self.register_level) task.module.add_pipeline(rst_q, init=rtl.RST_N) # add start registers start_q = rtl.Pipeline( f'{instance.start.name}_global', level=self.register_level, ) task.module.add_pipeline(start_q, self.start_q[0]) if instance.is_autorun: # autorun modules start when the global start signal is asserted task.module.add_logics([ ast.Always( sens_list=rtl.CLK_SENS_LIST, statement=ast.make_block( ast.make_if_with_block( cond=ast.Unot(rst_q[-1]), true=ast.NonblockingSubstitution( left=instance.start, right=rtl.FALSE, ), false=ast.make_if_with_block( cond=start_q[-1], true=ast.NonblockingSubstitution( left=instance.start, right=rtl.TRUE, ), ), )), ), ]) else: # set up state is_done_q = rtl.Pipeline( f'{instance.is_done.name}', level=self.register_level, ) done_q = rtl.Pipeline( f'{instance.done.name}_global', level=self.register_level, ) task.module.add_pipeline(is_done_q, instance.is_state(STATE10)) task.module.add_pipeline(done_q, self.done_q[0]) if_branch = (instance.set_state(STATE00)) else_branch = (( ast.make_if_with_block( cond=instance.is_state(STATE00), true=ast.make_if_with_block( cond=start_q[-1], true=instance.set_state(STATE01), ), ), ast.make_if_with_block( cond=instance.is_state(STATE01), true=ast.make_if_with_block( cond=instance.ready, true=ast.make_if_with_block( cond=instance.done, true=instance.set_state(STATE10), false=instance.set_state(STATE11), )), ), ast.make_if_with_block( cond=instance.is_state(STATE11), true=ast.make_if_with_block( cond=instance.done, true=instance.set_state(STATE10), ), ), ast.make_if_with_block( cond=instance.is_state(STATE10), true=ast.make_if_with_block( cond=done_q[-1], true=instance.set_state(STATE00), ), ), )) task.module.add_logics([ ast.Always( sens_list=rtl.CLK_SENS_LIST, statement=ast.make_block( ast.make_if_with_block( cond=ast.Unot(rst_q[-1]), true=if_branch, false=else_branch, )), ), ast.Assign( left=instance.start, right=instance.is_state(STATE01), ), ]) is_done_signals.append(is_done_q) # insert handshake signals task.module.add_signals(instance.handshake_signals) # add task module instances portargs = list(rtl.generate_handshake_ports(instance, rst_q)) for arg in instance.args: if arg.cat == Instance.Arg.Cat.SCALAR: portargs.append( ast.PortArg(portname=arg.port, argname=arg_table[arg.name][-1])) elif arg.cat == Instance.Arg.Cat.ISTREAM: portargs.extend( instance.task.module.generate_istream_ports( port=arg.port, arg=arg.name, )) portargs.extend(portarg for portarg in rtl.generate_peek_ports( rtl, port=arg.port, arg=arg.name) if portarg.portname in child_port_set) elif arg.cat == Instance.Arg.Cat.OSTREAM: portargs.extend( instance.task.module.generate_ostream_ports( port=arg.port, arg=arg.name, )) elif arg.cat == Instance.Arg.Cat.MMAP: portargs.extend( rtl.generate_m_axi_ports( module=instance.task.module, port=arg.port, arg=arg.mmap_name, arg_reg=arg_table[arg.name][-1].name, )) elif arg.cat == Instance.Arg.Cat.ASYNC_MMAP: for tag in async_mmap_args[arg]: portargs.extend( rtl.generate_async_mmap_ports( tag=tag, port=arg.port, arg=arg.mmap_name, instance=instance, )) task.module.add_instance( module_name=util.get_module_name(instance.task.name), instance_name=instance.name, ports=portargs, ) # instantiate async_mmap modules at the upper levels if task.is_upper: for arg in async_mmap_args: task.module.add_async_mmap_instance( name=arg.mmap_name, offset_name=arg_table[arg.name][-1], tags=async_mmap_args[arg], data_width=width_table[arg.name], ) return is_done_signals
def get_rtl(self, name: str, prefix: bool = True) -> str: return os.path.join(self.rtl_dir, (util.get_module_name(name) if prefix else name) + rtl.RTL_SUFFIX)