diff --git a/b_asic/architecture.py b/b_asic/architecture.py index f5040cbea7125ad6697732cf6e37772a49087182..db6f6a56937fdbb87048f89fcaec3ff372233e8b 100644 --- a/b_asic/architecture.py +++ b/b_asic/architecture.py @@ -104,7 +104,7 @@ class Resource: if outputs: outstrs = [f"<{outstr}> {outstr}" for outstr in outputs] ret += f"|{{{'|'.join(outstrs)}}}" - return ret + return "{" + ret + "}" @property def entity_name(self) -> str: @@ -243,16 +243,16 @@ class Architecture: self._memories = memories self._entity_name = entity_name self._direct_interconnects = direct_interconnects - self._variable_inport_to_resource: Dict[InputPort, Resource] = {} - self._variable_outport_to_resource: Dict[OutputPort, Resource] = {} + self._variable_inport_to_resource: Dict[InputPort, Tuple[Resource, int]] = {} + self._variable_outport_to_resource: Dict[OutputPort, Tuple[Resource, int]] = {} self._operation_inport_to_resource: Dict[InputPort, Resource] = {} self._operation_outport_to_resource: Dict[OutputPort, Resource] = {} - self._build_dicts() - # Validate input and output ports self.validate_ports() + self._build_dicts() + def _build_dicts(self): for pe in self.processing_elements: for operator in pe.processes: @@ -264,18 +264,20 @@ class Architecture: for memory in self.memories: for mv in memory: for read_port in mv.read_ports: - self._variable_inport_to_resource[read_port] = memory - self._variable_outport_to_resource[mv.write_port] = memory + self._variable_inport_to_resource[read_port] = (memory, 0) # Fix + self._variable_outport_to_resource[mv.write_port] = (memory, 0) # Fix if self._direct_interconnects: for di in self._direct_interconnects: di = cast(MemoryVariable, di) for read_port in di.read_ports: - self._variable_inport_to_resource[ - read_port - ] = self._operation_outport_to_resource[di.write_port] - self._variable_outport_to_resource[ - di.write_port - ] = self._operation_inport_to_resource[read_port] + self._variable_inport_to_resource[read_port] = ( + self._operation_outport_to_resource[di.write_port], + di.write_port.index, + ) + self._variable_outport_to_resource[di.write_port] = ( + self._operation_inport_to_resource[read_port], + read_port.index, + ) def validate_ports(self): # Validate inputs and outputs of memory variables in all the memories in this @@ -350,7 +352,9 @@ class Architecture: def get_interconnects_for_pe( self, pe: ProcessingElement - ) -> Tuple[List[Dict[Resource, int]], List[Dict[Resource, int]]]: + ) -> Tuple[ + List[Dict[Tuple[Resource, int], int]], List[Dict[Tuple[Resource, int], int]] + ]: """ Return lists of dictionaries with interconnect information for a ProcessingElement. @@ -402,7 +406,9 @@ class Architecture: return self._digraph()._repr_mimebundle_(include=["image/png"])["image/png"] def _digraph(self) -> Digraph: + edges = set() dg = Digraph(node_attr={'shape': 'record'}) + # dg.attr(rankdir="LR") for i, mem in enumerate(self._memories): dg.node(mem.entity_name, mem._struct_def()) for i, pe in enumerate(self._processing_elements): @@ -410,15 +416,25 @@ class Architecture: for pe in self._processing_elements: inputs, outputs = self.get_interconnects_for_pe(pe) for i, inp in enumerate(inputs): - for source, cnt in inp.items(): - dg.edge( - source.entity_name, f"{pe.entity_name}:in{i}", label=f"{cnt}" + for (source, port), cnt in inp.items(): + edges.add( + ( + f"{source.entity_name}:out{port}", + f"{pe.entity_name}:in{i}", + f"{cnt}", + ) ) for o, outp in enumerate(outputs): - for dest, cnt in outp.items(): - dg.edge( - f"{pe.entity_name}:out{o}", dest.entity_name, label=f"{cnt}" + for (dest, port), cnt in outp.items(): + edges.add( + ( + f"{pe.entity_name}:out{o}", + f"{dest.entity_name}:in{port}", + f"{cnt}", + ) ) + for src, dest, cnt in edges: + dg.edge(src, dest, label=cnt) return dg @property diff --git a/examples/secondorderdirectformiir_architecture.py b/examples/secondorderdirectformiir_architecture.py index ee1630098ceecd655bcf4c6b55809d0ee47a104c..2cb2022484882ae45ae69f693fc2a608cc2ad4e7 100644 --- a/examples/secondorderdirectformiir_architecture.py +++ b/examples/secondorderdirectformiir_architecture.py @@ -84,3 +84,31 @@ for i, mem in enumerate(mem_vars_set): # %% # Create architecture arch = Architecture({p1, p2, p_in, p_out}, memories, direct_interconnects=direct) + +# %% +# The architecture can be rendered in enriched shells. +# +# .. graphviz:: +# +# digraph { +# node [shape=record] +# memory1 [label="{{<in0> in0}|memory1|{<out0> out0}}"] +# memory0 [label="{{<in0> in0}|memory0|{<out0> out0}}"] +# memory2 [label="{{<in0> in0}|memory2|{<out0> out0}}"] +# in [label="{in|{<out0> out0}}"] +# out [label="{{<in0> in0}|out}"] +# cmul [label="{{<in0> in0}|cmul|{<out0> out0}}"] +# adder [label="{{<in0> in0|<in1> in1}|adder|{<out0> out0}}"] +# memory1:out0 -> adder:in1 [label=1] +# cmul:out0 -> adder:in0 [label=1] +# cmul:out0 -> memory0:in0 [label=3] +# memory0:out0 -> adder:in0 [label=1] +# adder:out0 -> adder:in1 [label=1] +# memory1:out0 -> cmul:in0 [label=5] +# memory0:out0 -> adder:in1 [label=2] +# adder:out0 -> memory1:in0 [label=2] +# adder:out0 -> out:in0 [label=1] +# memory2:out0 -> adder:in0 [label=2] +# cmul:out0 -> memory2:in0 [label=2] +# in:out0 -> cmul:in0 [label=1] +# } diff --git a/test/test_architecture.py b/test/test_architecture.py index b100f23f5c7a7208ebcc4ec9bf1ab326cb451b2a..e7b42e893895f1814e1a6009bd8158c9d0b6e89a 100644 --- a/test/test_architecture.py +++ b/test/test_architecture.py @@ -89,9 +89,9 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule): s = ( 'digraph {\n\tnode [shape=record]\n\t' + pe._entity_name - + ' [label="{<in0> in0|<in1> in1}|' + + ' [label="{{<in0> in0|<in1> in1}|' + pe._entity_name - + '|{<out0> out0}"]\n}' + + '|{<out0> out0}}"]\n}' ) assert pe._digraph().source in (s, s + '\n') @@ -107,8 +107,8 @@ def test_architecture(schedule_direct_form_iir_lp_filter: Schedule): for i, memory in enumerate(memories): memory.set_entity_name(f"MEM{i}") s = ( - 'digraph {\n\tnode [shape=record]\n\tMEM0 [label="{<in0> in0}|MEM0|{<out0>' - ' out0}"]\n}' + 'digraph {\n\tnode [shape=record]\n\tMEM0 [label="{{<in0> in0}|MEM0|{<out0>' + ' out0}}"]\n}' ) assert memory._digraph().source in (s, s + '\n')