def generate_m_axi_ports( module: Module, port: str, arg: str, arg_reg: str = '', ) -> Iterator[ast.PortArg]: """Generate AXI mmap ports that instantiate given module. Args: module (Module): Module that needs to be instantiated. port (str): Port name in the instantiated module. arg (str): Argument name in the instantiating module. arg_reg (str, optional): Registered argument name. Defaults to ''. Raises: ValueError: If the offset port cannot be found in the instantiated module. Yields: Iterator[ast.PortArg]: PortArgs. """ for suffix in M_AXI_SUFFIXES: yield ast.make_port_arg(port=M_AXI_PREFIX + port + suffix, arg=M_AXI_PREFIX + arg + suffix) for suffix in '_offset', '_data_V', '_V', '': port_name = module.find_port(prefix=port, suffix=suffix) if port_name is not None: if port_name != port + suffix: _logger.warn( f"unexpected offset port `{port_name}' in module" f" `{module.name}'; please double check if this is the " f"offset port for m_axi port `{port}'") yield ast.make_port_arg(port=port_name, arg=arg_reg or arg) break else: raise ValueError(f'cannot find offset port for {port}')
def generate_istream_ports( self, port: str, arg: str, ) -> Iterator[ast.PortArg]: for suffix in ISTREAM_SUFFIXES: arg_name = wire_name(arg, suffix) # read port yield ast.make_port_arg( port=self.get_port_of(port, suffix).name, arg=arg_name, ) if STREAM_PORT_DIRECTION[suffix] == 'output': arg_name = '' # peek port match = match_array_name(port) if match is None: peek_port = f'{port}_peek' else: peek_port = f'{match[0]}_peek[{match[1]}]' yield ast.make_port_arg( port=self.get_port_of(peek_port, suffix).name, arg=arg_name, )
def generate_async_mmap_ports( tag: str, port: str, arg: str, instance: tapa.instance.Instance) -> Iterator[ast.PortArg]: # TODO: reuse functions that generate i/ostream ports prefix = port + '_' + tag for suffix in ASYNC_MMAP_SUFFIXES[tag]: arg_name = async_mmap_arg_name( arg=arg, tag=tag, suffix=suffix, ) port_name = instance.task.module.find_port(prefix=prefix, suffix=suffix) if port_name is not None: # Make sure Eot is always 1'b0. if suffix == ISTREAM_SUFFIXES[0]: arg_name = f"{{1'b0, {arg_name}}}" _logger.debug('`%s.%s` is connected to async_mmap port `%s.%s`', instance.name, port_name, arg, tag) yield ast.make_port_arg(port=port_name, arg=arg_name) # Generate peek ports. if ASYNC_MMAP_SUFFIXES[tag] is ISTREAM_SUFFIXES: port_name = instance.task.module.find_port(prefix + '_peek', suffix) if port_name is not None: # Ignore read enable from peek ports. if STREAM_PORT_DIRECTION[suffix] == 'input': _logger.debug('`%s.%s` is connected to async_mmap port `%s.%s`', instance.name, port_name, arg, tag) else: arg_name = '' yield ast.make_port_arg(port=port_name, arg=arg_name)
def generate_handshake_ports( instance: tapa.instance.Instance, rst_q: Pipeline, ) -> Iterator[ast.PortArg]: yield ast.make_port_arg(port=HANDSHAKE_CLK, arg=CLK) yield ast.make_port_arg(port=HANDSHAKE_RST_N, arg=rst_q[-1]) yield ast.make_port_arg(port=HANDSHAKE_START, arg=instance.start) for port in HANDSHAKE_OUTPUT_PORTS: yield ast.make_port_arg( port=port, arg="" if instance.is_autorun else wire_name(instance.name, port), )
def generate_ostream_ports( self, port: str, arg: str, ) -> Iterator[ast.PortArg]: for suffix in OSTREAM_SUFFIXES: yield ast.make_port_arg( port=self.get_port_of(port, suffix).name, arg=wire_name(arg, suffix), )
def generate_peek_ports(verilog, port: str, arg: str) -> Iterator[ast.PortArg]: match = match_array_name(port) if match is None: port = f'{port}_peek_V' else: port = f'{match[0]}_peek_V_{match[1]}' for suffix in verilog.ISTREAM_SUFFIXES: if verilog.STREAM_PORT_DIRECTION[suffix] == 'input': arg_name = wire_name(arg, suffix) else: arg_name = '' yield ast.make_port_arg(port=port + suffix, arg=arg_name)
def generate_async_mmap_ports( tag: str, port: str, arg: str, instance: tapa.instance.Instance) -> Iterator[ast.PortArg]: prefix = port + '_' + tag + '_V_' for suffix in async_mmap_suffixes(tag): port_name = instance.task.module.find_port(prefix=prefix, suffix=suffix) if port_name is not None: yield ast.make_port_arg( port=port_name, arg=async_mmap_arg_name( arg=arg, tag=tag, suffix=suffix, ), )
def ports() -> Iterator[ast.PortArg]: yield ast.make_port_arg(port='clk', arg=CLK) yield ast.make_port_arg(port='reset', arg=rst_q[-1]) yield from ( ast.make_port_arg(port=port_name, arg=wire_name(name, arg_suffix)) for port_name, arg_suffix in zip(FIFO_READ_PORTS, ISTREAM_SUFFIXES)) yield ast.make_port_arg(port=FIFO_READ_PORTS[-1], arg=TRUE) yield from ( ast.make_port_arg(port=port_name, arg=wire_name(name, arg_suffix)) for port_name, arg_suffix in zip(FIFO_WRITE_PORTS, OSTREAM_SUFFIXES)) yield ast.make_port_arg(port=FIFO_WRITE_PORTS[-1], arg=TRUE)
def add_m_axi( self, width_table: Dict[str, int], tcl_files: Dict[str, str], ) -> None: for arg_name, (m_axi_id_width, args) in self.mmaps.items(): # add m_axi ports to the arg list self.module.add_m_axi( name=arg_name, data_width=width_table[arg_name], id_width=m_axi_id_width or None, ) if len(args) == 1: continue # add AXI interconnect if necessary assert len(args) <= 16, f'too many ports connected to {arg_name}' assert m_axi_id_width is not None s_axi_id_width = max( arg.instance.task.get_id_width(arg.port) or 0 for arg in args) portargs = [ ast.make_port_arg(port='INTERCONNECT_ACLK', arg=rtl.HANDSHAKE_CLK), ast.make_port_arg( port='INTERCONNECT_ARESETN', arg=rtl.HANDSHAKE_RST_N, ), ast.make_port_arg(port='M00_AXI_ACLK', arg=rtl.HANDSHAKE_CLK), ast.make_port_arg(port='M00_AXI_ARESET_OUT_N', arg=''), ] for axi_chan, axi_ports in rtl.M_AXI_PORTS.items(): for axi_port, direction in axi_ports: m_axi_arg = f'{rtl.M_AXI_PREFIX}{arg_name}_{axi_chan}{axi_port}' if axi_port == 'ID' and direction == 'input': m_axi_arg = ( f"{{{s_axi_id_width + 4 - m_axi_id_width}'d0, " f"{m_axi_arg}}}") portargs.append( ast.make_port_arg( port=f'M00_AXI_{axi_chan}{axi_port}', arg=m_axi_arg, )) for idx, arg in enumerate(args): portargs += ( ast.make_port_arg(port=f'S{idx:02d}_AXI_ACLK', arg=rtl.HANDSHAKE_CLK), ast.make_port_arg(port=f'S{idx:02d}_AXI_ARESET_OUT_N', arg=''), ) wires = [] for axi_chan, axi_ports in rtl.M_AXI_PORTS.items(): for axi_port, _ in axi_ports: wire_name = (f'{rtl.M_AXI_PREFIX}{arg.mmap_name}_' f'{axi_chan}{axi_port}') wires.append( ast.Wire( name=wire_name, width=rtl.get_m_axi_port_width( port=axi_port, data_width=width_table[arg_name], id_width=arg.instance.task.get_id_width( arg.port), ))) portargs.append( ast.make_port_arg( port=f'S{idx:02d}_AXI_{axi_chan}{axi_port}', arg=wire_name, )) self.module.add_signals(wires) data_width = max(width_table[arg_name], 32) assert data_width in {32, 64, 128, 256, 512, 1024} module_name = (f'axi_interconnect_{data_width}b_' f'{s_axi_id_width}t_x{len(args)}') s_axi_data_width = ' \\\n '.join( f'CONFIG.S{idx:02d}_AXI_DATA_WIDTH {data_width}' for idx in range(len(args))) s_axi_read_acceptance = ' \\\n '.join( f'CONFIG.S{idx:02d}_AXI_READ_ACCEPTANCE 16' for idx in range(len(args))) s_axi_write_acceptance = ' \\\n '.join( f'CONFIG.S{idx:02d}_AXI_WRITE_ACCEPTANCE 16' for idx in range(len(args))) tcl_files.setdefault( module_name, f'''\ create_ip \\ -name axi_interconnect \\ -vendor xilinx.com \\ -library ip \\ -version 1.7 \\ -module_name {module_name} set_property -dict [list \\ CONFIG.AXI_ADDR_WIDTH 64 \\ CONFIG.NUM_SLAVE_PORTS {len(args)} \\ CONFIG.THREAD_ID_WIDTH {s_axi_id_width} \\ CONFIG.INTERCONNECT_DATA_WIDTH {data_width} \\ CONFIG.M00_AXI_DATA_WIDTH {data_width} \\ {s_axi_data_width} \\ CONFIG.M00_AXI_READ_ISSUING 16 \\ {s_axi_read_acceptance} \\ CONFIG.M00_AXI_WRITE_ISSUING 16 \\ {s_axi_write_acceptance} \\ ] [get_ips {module_name}] set_property generate_synth_checkpoint false [get_files {module_name}.xci] generate_target {{synthesis simulation}} [get_files {module_name}.xci] ''') self.module.add_instance( module_name=module_name, instance_name=f'{module_name}__{arg_name}', ports=portargs, )
def add_async_mmap_instance( self, name: str, tags: Iterable[str], data_width: int, addr_width: int = 64, buffer_size: Optional[int] = None, max_wait_time: int = 3, max_burst_len: Optional[int] = None, offset_name: str = '', ) -> 'Module': rst_q = Pipeline(f'{name}__rst', level=self.register_level) self.add_pipeline(rst_q, init=ast.Unot(RST_N)) paramargs = [ ast.ParamArg(paramname='DataWidth', argname=ast.Constant(data_width)), ast.ParamArg(paramname='DataWidthBytesLog', argname=ast.Constant( (data_width // 8 - 1).bit_length())), ] portargs = [ ast.make_port_arg(port='clk', arg=CLK), ast.make_port_arg(port='rst', arg=rst_q[-1]), ] paramargs.append( ast.ParamArg(paramname='AddrWidth', argname=ast.Constant(addr_width))) if buffer_size: paramargs.extend( (ast.ParamArg(paramname='BufferSize', argname=ast.Constant(buffer_size)), ast.ParamArg(paramname='BufferSizeLog', argname=ast.Constant( (buffer_size - 1).bit_length())))) max_wait_time = max(1, max_wait_time) paramargs.append( ast.ParamArg(paramname='WaitTimeWidth', argname=ast.Constant(max_wait_time.bit_length()))) portargs.append( ast.make_port_arg(port='max_wait_time', arg="{}'d{}".format(max_wait_time.bit_length(), max_wait_time))) if max_burst_len is None: max_burst_len = max(0, 4096 // data_width - 1) paramargs.append( ast.ParamArg(paramname='BurstLenWidth', argname=ast.Constant( max(1, max_burst_len.bit_length())))) portargs.append( ast.make_port_arg(port='max_burst_len', arg="{}'d{}".format( max(1, max_burst_len.bit_length()), max_burst_len))) for channel, ports in M_AXI_PORTS.items(): for port, direction in ports: portargs.append( ast.make_port_arg( port=f'{M_AXI_PREFIX}{channel}{port}', arg=f'{M_AXI_PREFIX}{name}_{channel}{port}')) tags = set(tags) for tag in 'read_addr', 'read_data', 'write_addr', 'write_data': for suffix in async_mmap_suffixes(tag=tag): if tag in tags: arg = async_mmap_arg_name(arg=name, tag=tag, suffix=suffix) if tag.endswith('_addr') and suffix.endswith('_din'): elem_size_bytes_m1 = data_width // 8 - 1 arg = "{name} + {{{arg}[{}:0], {}'d0}}".format( addr_width - elem_size_bytes_m1.bit_length() - 1, elem_size_bytes_m1.bit_length(), arg=arg, name=offset_name or name) else: if suffix.endswith('_read') or suffix.endswith('_write'): arg = "1'b0" elif suffix.endswith('_din'): arg = "'d0" else: arg = '' portargs.append(ast.make_port_arg(port=tag + suffix, arg=arg)) return self.add_instance(module_name='async_mmap', instance_name=async_mmap_instance_name(name), ports=portargs, params=paramargs)
def generate_ostream_ports(port: str, arg: str) -> Iterator[ast.PortArg]: for suffix in OSTREAM_SUFFIXES: yield ast.make_port_arg(port=fifo_port_name(port, suffix), arg=wire_name(arg, suffix))