def generate_flow_network(self, fig_subgraph_view) -> MINTDevice: # TODO - For now just assume that the networks basically are a bunch # of nodes with nets/channels connecting them ret = MINTDevice("flow_network_temp") mint_layer = ret.create_mint_layer("0", "0", 0, MINTLayerType.FLOW) for node in fig_subgraph_view.nodes: n = MINTNode("node_{}".format(node), mint_layer) ret.add_component(n) self._store_fig_netlist_name(node, n.ID) i = 1 for node in fig_subgraph_view.nodes: # Create the channel between these nodes channel_name = "c_{}".format(i) i += 1 params = dict() params["channelWidth"] = 400 source = MINTTarget("node_{}".format(node)) sinks = [] # Add all the outgoing edges for edge in fig_subgraph_view.out_edges(node): tar = edge[1] if tar not in fig_subgraph_view.nodes: # We skip because this might be a weird edge that we were not supposed # to have in this network continue sinks.append(MINTTarget("node_{}".format(tar))) ret.create_mint_connection(channel_name, "CHANNEL", params, source, sinks, "0") return ret
class MINTCompiler(mintListener): """Primary ANTLR listener class for the compiler""" def __init__(self): super().__init__() self.current_device: MINTDevice = MINTDevice("DEFAULT_NAME") self.current_block_id = 0 self.current_layer_id = 0 self.flow_layer_count = 0 self.control_layer_count = 0 self.integration_layer_count = 0 self.current_entity: Optional[str] = None self.current_params: Dict = {} self._current_layer: Optional[Layer] = None def enterNetlist(self, ctx: mintParser.NetlistContext): self.current_device = MINTDevice("DEFAULT_NAME") def exitNetlist(self, ctx: mintParser.NetlistContext): if self.current_device is None: raise Exception("Could not find the device") def enterHeader(self, ctx: mintParser.HeaderContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) if ctx.device_name is None: raise Exception("Could not find Device Name") self.current_device.device.name = ctx.device_name.text def exitLayerBlock(self, ctx: mintParser.LayerBlockContext): # Increement teh layer block self.current_block_id += 1 def enterFlowBlock(self, ctx: mintParser.FlowBlockContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) layer = self.current_device.create_mint_layer( str(self.current_layer_id), str(self.flow_layer_count), str(self.current_block_id), MINTLayerType.FLOW, ) self._current_layer = layer self.flow_layer_count += 1 self.current_layer_id += 1 def enterControlBlock(self, ctx: mintParser.ControlBlockContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) layer = self.current_device.create_mint_layer( str(self.current_layer_id), str(self.control_layer_count), str(self.current_block_id), MINTLayerType.CONTROL, ) self._current_layer = layer self.control_layer_count += 1 self.current_layer_id += 1 def enterIntegrationBlock(self, ctx: mintParser.IntegrationBlockContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) layer = self.current_device.create_mint_layer( str(self.current_layer_id), str(self.integration_layer_count), str(self.current_block_id), MINTLayerType.INTEGRATION, ) self._current_layer = layer self.integration_layer_count += 1 self.current_layer_id += 1 def enterEntity(self, ctx: mintParser.EntityContext): self.current_entity = ctx.getText() def enterParamsStat(self, ctx: mintParser.ParamsStatContext): self.current_params = {} def enterIntParam(self, ctx: mintParser.IntParamContext): value = ctx.value().getText() # type: ignore key = ctx.param_element().getText() # type: ignore self.current_params[key] = int(value) def enterBoolParam(self, ctx: mintParser.BoolParamContext): if ctx.boolvalue.getText() == "YES": value = True else: value = False key = ctx.param_element.getText() self.current_params[key] = value def enterLengthParam(self, ctx: mintParser.LengthParamContext): value = float(ctx.value().getText()) # type: ignore self.current_params["length"] = value def enterSpacingParam(self, ctx: mintParser.SpacingParamContext): value = float(ctx.value().getText()) # type: ignore self.current_params["spacing"] = value def enterWidthParam(self, ctx: mintParser.WidthParamContext): value = ctx.value().getText() # type: ignore if ctx.key is None: raise AssertionError key = ctx.key.text if key is None: raise Exception("Error in parsing the width parameter") if key == "w": key = "width" self.current_params[key] = int(value) def enterFlowStat(self, ctx: mintParser.FlowStatContext): self.current_entity = None self.current_params = {} def enterControlStat(self, ctx: mintParser.ControlStatContext): self.current_entity = None self.current_params = {} def exitPrimitiveStat(self, ctx: mintParser.PrimitiveStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) entity = self.current_entity if entity is None: raise Exception("Could not find the technology for the pimitive") # Loop for each of the components that need to be created with this param for ufname in ctx.ufnames().ufname(): # type: ignore if self._current_layer is None: raise Exception("Current layer is set to None") if not ( self._current_layer is not None and self._current_layer.ID is not None ): raise AssertionError self.current_device.create_mint_component( ufname.getText(), entity, self.current_params, [self._current_layer.ID], ) def exitBankDeclStat(self, ctx: mintParser.BankDeclStatContext): entity = self.current_entity if entity is None: raise Exception("Could not find the technology for the primitive") # Clean up the constraint specific params self._cleanup_bank_params() for ufname in ctx.ufnames().ufname(): # type: ignore component_name = ufname.getText() if self._current_layer is None: raise AssertionError self.current_device.create_mint_component( component_name, entity, self.current_params, [self._current_layer.ID], ) def exitBankGenStat(self, ctx: mintParser.BankGenStatContext): entity = self.current_entity if entity is None: raise Exception("Could not find the technology for the primitive") self._cleanup_bank_params() if ctx.dim is None: raise AssertionError dim = int(ctx.dim.text) name = ctx.ufname().getText() # type: ignore for i in range(1, dim + 1): component_name = name + "_" + str(i) if self._current_layer is None: raise Exception("Current Layer not Set") if not ( self._current_layer is not None and self._current_layer.ID is not None ): raise AssertionError self.current_device.create_mint_component( component_name, entity, self.current_params, [self._current_layer.ID] ) def exitGridDeclStat(self, ctx: mintParser.GridDeclStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) entity = self.current_entity if entity is None: raise Exception("Could not find the technology for the primitive") self._cleanup_grid_params() for ufname in ctx.ufnames().ufname(): # type: ignore component_name = ufname.getText() if self._current_layer is None: raise AssertionError self.current_device.create_mint_component( component_name, entity, self.current_params, [self._current_layer.ID], ) def exitChannelStat(self, ctx: mintParser.ChannelStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) entity = self.current_entity if entity is None: entity = "CHANNEL" connection_name = ctx.ufname().getText() # type: ignore source_target = ctx.uftarget()[0] # type: ignore source_id = source_target.ID().getText() if self.current_device.device.component_exists(source_id) is False: raise Exception( "Error ! - Could not find the component '{}' in device '{}'".format( source_id, self.current_device.device.name ) ) if source_target.INT(): source_port = source_target.INT().getText() else: source_port = None # source_uftarget = Target(component_id=source_id, port=source_port) source_uftarget = Target(component_id=source_id, port=source_port) sink_target = ctx.uftarget()[1] # type: ignore sink_id = sink_target.ID().getText() if self.current_device.device.component_exists(sink_id) is False: raise Exception( "Error ! - Could not find the component '{}' in device '{}'".format( sink_id, self.current_device.device.name ) ) if sink_target.INT(): sink_port = sink_target.INT().getText() else: sink_port = None sink_uftarget = Target(component_id=sink_id, port=sink_port) self._cleanup_channel_params() # Create a connection between the different components in the device if not (self._current_layer is not None and self._current_layer.ID is not None): raise AssertionError self.current_device.create_mint_connection( connection_name, entity, self.current_params, source_uftarget, [sink_uftarget], self._current_layer.ID, ) def exitNetStat(self, ctx: mintParser.NetStatContext): entity = self.current_entity if entity is None: entity = "NET" connection_name = ctx.ufname().getText() # type: ignore source_target = ctx.uftarget() source_id = source_target.ID().getText() # type: ignore if source_target.INT(): # type: ignore source_port = source_target.INT().getText() # type: ignore else: source_port = None source_uftarget = Target(component_id=source_id, port=source_port) sink_uftargets = [] for sink_target in ctx.uftargets().uftarget(): # type: ignore sink_id = sink_target.ID().getText() if sink_target.INT(): sink_port = sink_target.INT().getText() else: sink_port = None sink_uftargets.append(Target(component_id=sink_id, port=sink_port)) if not (self._current_layer is not None and self._current_layer.ID is not None): raise AssertionError self.current_device.create_mint_connection( connection_name, entity, self.current_params, source_uftarget, sink_uftargets, self._current_layer.ID, ) def exitSpanStat(self, ctx: mintParser.SpanStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) entity = self.current_entity if entity is None: raise Exception("Could not find the technology for the pimitive") # pipe in the in / out values to params for sizing if ctx.indim is not None: in_value = int(ctx.indim.text) self.current_params["in"] = in_value if ctx.outdim is not None: out_value = int(ctx.outdim.text) self.current_params["out"] = out_value # Loop for each of the components that need to be created with this param for ufname in ctx.ufnames().ufname(): # type: ignore if self._current_layer is None: raise AssertionError self.current_device.create_mint_component( ufname.getText(), entity, self.current_params, [self._current_layer.ID], ) def exitNodeStat(self, ctx: mintParser.NodeStatContext): entity = "NODE" if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) # Loop for each of the components that need to be created with this param if not (self._current_layer is not None and self._current_layer.ID is not None): raise AssertionError for ufname in ctx.ufnames().ufname(): # type: ignore self.current_device.create_mint_component( ufname.getText(), entity, self.current_params, [self._current_layer.ID], ) def exitValveStat(self, ctx: mintParser.ValveStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) entity = self.current_entity if entity is None: logging.error("Could not find entitry information for valve") raise Exception("Could not find entitry information for valve") valve_name = ctx.ufname()[0].getText() # type: ignore if not (self._current_layer is not None and self._current_layer.ID is not None): raise AssertionError valve_component = self.current_device.create_mint_component( valve_name, entity, self.current_params, [self._current_layer.ID], ) connection_name = ctx.ufname()[1].getText() # type: ignore valve_connection = self.current_device.device.get_connection(connection_name) if valve_connection is None: raise Exception( "Error: Could not find connection '{}' in device '{}'".format( connection_name, self.current_device.device.name ) ) self.current_device.device.map_valve(valve_component, valve_connection) def enterViaStat(self, ctx: mintParser.ViaStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) for ufname in ctx.ufnames().ufname(): self.current_device.add_via(ufname.getText(), []) def enterTerminalStat(self, ctx: mintParser.TerminalStatContext): if self.current_device is None: raise Exception( "Error Initializing the device. Could not find the current device" ) terminal_name = ctx.ufname().getText() pin_number = int(ctx.INT.getText()) if not (self._current_layer is not None and self._current_layer.ID is not None): raise AssertionError self.current_device.add_terminal( terminal_name, pin_number, self._current_layer.ID, ) def _cleanup_bank_params(self): if "spacing" in self.current_params: del self.current_params["spacing"] def _cleanup_grid_params(self): if "horizontalSpacing" in self.current_params: del self.current_params["horizontalSpacing"] if "verticalSpacing" in self.current_params: del self.current_params["verticalSpacing"] def _cleanup_channel_params(self): if "length" in self.current_params: del self.current_params["length"]
def generate(module: Module, library: MappingLibrary) -> MINTDevice: construction_graph = ConstructionGraph() name_generator = NameGenerator() cur_device = MINTDevice(module.name) # Add a MINT Layer so that the device has something to work with cur_device.create_mint_layer("0", "0", 0, MINTLayerType.FLOW) # TODO - I need to change this DummyStrategy later on if library.name == "dropx": active_strategy = DropXStrategy(construction_graph, module.FIG) elif library.name == "mars": raise NotImplementedError() elif library.name == "hmlp": raise NotImplementedError() else: active_strategy = DummyStrategy(construction_graph, module.FIG) # First go through all the interactions in the design # IF interaction is mix/sieve/divide/dilute/meter look at the library # to get all the options available and set them up as options for the # construction graph to pick and choose from the options. # # FUTURE WORK # # Do the regex matching to find the mapping options # This means that we might need to have a forest of construction of graphs # as there would be alternatives for each type of mapping for interaction in module.FIG.get_interactions(): operator_candidates = library.get_operators( interaction_type=interaction.type) cn = ConstructionNode(interaction.id) # if isinstance(interaction, ValueNode): # continue for operator_candidate in operator_candidates: # TODO: This will change in the future when we can match subgraphs correctly if isinstance(interaction, (FluidNumberInteraction, FluidIntegerInteraction)): # Basically add the value node id into the subgraph view also node_ids = [ module.FIG.get_fignode(edge[0]).id for edge in module.FIG.in_edges(interaction.id) if isinstance(module.FIG.get_fignode(edge[0]), ValueNode) ] node_ids.append(interaction.id) sub_graph = module.FIG.subgraph(node_ids) else: sub_graph = module.FIG.subgraph(interaction.id) mapping_option = MappingOption(operator_candidate, sub_graph) cn.add_mapping_option(mapping_option) construction_graph.add_construction_node(cn) # Generate all ports necessary for the Explicitly declared IO # ------- # Generate the flow layer IO. These are typically declared explicitly # TODO - Figure out how we should generate the construction nodes for control networks for io_ref in module.io: if io_ref.type is IOType.CONTROL: continue for io in io_ref.vector_ref: cn = ConstructionNode(io.id) sub_graph = module.FIG.subgraph(io.id) mapping_candidate = library.get_default_IO() mapping_option = MappingOption(mapping_candidate, sub_graph) cn.add_mapping_option(mapping_option) construction_graph.add_construction_node(cn) # Map the storage and pump elements to their own individual construction graph nodes for fig_node_id in list(module.FIG.nodes): fig_node = module.FIG.get_fignode(fig_node_id) if isinstance(fig_node, Pump): cn = ConstructionNode(fig_node.id) sub_graph = module.FIG.subgraph(fig_node_id) mapping_candidates = library.get_pump_entries() for mapping_candidate in mapping_candidates: mapping_option = MappingOption(mapping_candidate, sub_graph) cn.add_mapping_option(mapping_option) elif isinstance(fig_node, Storage): cn = ConstructionNode(fig_node.id) sub_graph = module.FIG.subgraph(fig_node_id) mapping_candidates = library.get_storage_entries() for mapping_candidate in mapping_candidates: mapping_option = MappingOption(mapping_candidate, sub_graph) cn.add_mapping_option(mapping_option) # TODO - Validate if this is a legit way to do things mappings = module.get_explicit_mappings() override_network_mappings(mappings, library, module.FIG, construction_graph) # TODO - Go through the different flow-flow edge networks to generate construction nodes # specific to these networks, Conditions: # if its a 1-1 flow-flow connection, then create a construction node for the two flow nodes # if its a 1-n / n-1 / n-n construction nodes, then create a construction node capturing the whole network # TODO - Deal with coverage issues here since we need to figure out what are the flow networks, # that we want to match first and then ensure that they're no included on any list cn_nodes = get_flow_flow_candidates(module, active_strategy) for cn in cn_nodes: construction_graph.add_construction_node(cn) # Apply all the explicit mappings in the module to the nodes, overwriting # the options from the library to match against # TODO - Modify Explicit Mapping Data structure # Find all the explicit mappings and override them in the construction graph override_mappings(mappings, library, module.FIG, construction_graph) # Whittle Down the mapping options here to only include the requried single candidates # TODO - Check what library is being used and use the required library here active_strategy.reduce_mapping_options() # TODO - Consider what needs to get done for a combinatorial design space # ---------------- # Generate edges in the construction graph, these edges will guide the generation/ # reduction of path and pipelineing that needs to get done for mars devices construction_graph.generate_edges(module.FIG) # TODO - Extract all pass through networks eliminate_passthrough_nodes(construction_graph) # Now since all the mapping options are finalized Extract the netlist necessary construction_graph.construct_components(name_generator, cur_device) construction_graph.construct_connections(name_generator, cur_device) # Finally join all the netlist pieces attached to the construction nodes # and the input/output/load/carrier flows # TODO - MINIMIZE - carrier / load flows - this might require us to generate # multiple netlist options and pick the best construction_graph.generate_flow_cn_edges(module) construction_graph.generate_control_cn_edges(module) # Generate all the unaccounted carriers and waste output lines necessary # for this to function connect_orphan_IO() # Size the component netlist active_strategy.size_netlist(cur_device) return cur_device