-
Notifications
You must be signed in to change notification settings - Fork 76
Dataflow Analysis
The dataflow analysis plugin aims to recover word-level registers from the unstructured sea of gates. It identifies registers by analyzing shared control signals of flip-flops and by leveraging structural information such as register stages. For details on the methodology, see the original paper.
To execute dataflow analysis in its default configuration, run:
from hal_plugins import dataflow
res = dataflow.Dataflow.analyze(netlist)
You can fine-tune the algorithm by enabling/disabling register stage identification, specifying register sizes most likely to be found within the analyzed netlist (e.g., 32
for a 32-bit CPU), setting the minimum register size, or providing already identified registers. This is done using the Dataflow.Configuration
class as follows:
config = dataflow.Dataflow.Configuration() # create a default configuration object
config = config.with_expected_sizes([32, 64]) # set expected register sizes to 32 and 64
config = config.with_min_group_size(4) # set minimum register size to 4
config = config.with_register_stage_identification() # enable register stage identification
config = config.with_known_groups(some_list_of_groups) # provide previously identified register groups
res = dataflow.Dataflow.analyze(netlist, config)
Please note that registers smaller than the minimum register size may still be output if no larger register could be reconstructed, but will have low priority during the voting that is part of the dataflow analysis. Hence, if a larger register is plausible, it will be preferred by the algorithm. Furthermore, known groups may be provided as a list of modules, a list of groupings, a list of lists of gates, or a list of lists of gate IDs.
Running dataflow analysis using Dataflow.analyze
produces an object of class Dataflow.Result
that enables interaction with its results. It allows access to the register groups and provides a set of utility functions to perform simple operations on the result, as shown below:
res = dataflow.Dataflow.analyze(netlist)
res.get_groups() # returns all register groups as a dictionary from group ID to a set of the gates contained in the group
res.get_gates_of_group(3) # returns all gates belonging to the register group with ID 3
res.get_group_id_of_gate(some_gate) # returns the ID of the register group that the given gate belongs to
res.get_group_predecessors(3) # returns the predecessor register groups of the group with ID 3 as a set of group IDs
res.get_group_successors(3) # returns the successor register groups of the group with ID 3 as a set of group IDs
res.get_group_control_nets(3, hal_py.PinType.clock) # returns a set of nets connected to the clock input of gates within group with ID 3
Manual modifications can be applied to the result of dataflow analysis by merging or splitting existing register groups.
merged_group = res.merge_groups([3, 4]) # merges the groups with IDs 3 and 4
split_groups = res.split_group(3, [gates_1, gates_2]) # splits group with ID 3 into a group containing 'gates_1' and another one containing 'gates_2'
Finally, Dataflow.Result
provides functions to write the results to a file or even merge it into the netlist. All these function take an optional argument that allows to restrict them to only consider selected groups.
res = dataflow.Dataflow.analyze(netlist)
res.write_dot("some/file/path/result.txt") # writes a textual representation of the result to the specified file
res.write_dot("some/file/path/graph.dot", {4, 5, 6}) # writes a .dot file describing the dataflow graph, but only includes register groups with IDs 4, 5, and 6
res.create_modules({4, 5, 6}) # creates modules for the register groups with ID 4, 5, and 6 within the netlist