def pe_exclusivity(cgra : MRRG, design : Design, vars : Modeler, solver : Solver) -> Term: ''' Assert all PEs are used at most one time ''' bv = solver.BitVec(len(design.operations)) c = [] for pe in cgra.functional_units: pe_vars = vars.anonymous_var(bv) for idx, op in enumerate(design.operations): c.append(pe_vars[idx] == vars[pe, op]) c.append(_is_one_hot_or_0(pe_vars, solver)) return solver.And(c)
def op_placement(cgra : MRRG, design : Design, vars : Modeler, solver : Solver) -> Term: ''' Assert all ops are placed exactly one time unless they can be duplicated in which case assert they are placed ''' bv = solver.BitVec(len(cgra.functional_units)) c = [] for op in design.operations: if op.duplicate: c.append(ft.reduce(solver.BVOr, (vars[pe, op] for pe in cgra.functional_units)) == 1) else: op_vars = vars.anonymous_var(bv) for idx,pe in enumerate(cgra.functional_units): c.append(op_vars[idx] == vars[pe, op]) c.append(_is_one_hot(op_vars, solver)) return solver.And(c)
def route_exclusivity(cgra : MRRG, design : Design, vars : Modeler, solver : Solver) -> Term: ''' each routing node is used for at most one value for all node in nodes: popcount(vars[node, value] for value in values) <= 1 ''' bv = solver.BitVec(len(design.values)) c = [] for node in cgra.all_nodes: node_vars = vars.anonymous_var(bv) for idx, value in enumerate(design.values): c.append(node_vars[idx] == vars[node, value]) c.append(_is_one_hot_or_0(node_vars, solver)) return solver.And(c)
def output_connectivity(cgra : MRRG, design : Design, vars : Modeler, solver : Solver) -> Term: ''' if node used to route a value then exactly one of its outputs also routes that value ''' c = [] for node in cgra.all_nodes: bv = solver.BitVec(len(node.outputs.values())) for value in design.values: if isinstance(node, mrrg.FU_Port): continue for dst in value.dsts: v = vars[node, value, dst] i_vars = vars.anonymous_var(bv) for idx, n in enumerate(node.outputs.values()): c.append(i_vars[idx] == vars[n, value, dst]) c.append(solver.Or(v == 0, _is_one_hot(i_vars, solver))) return solver.And(c)
def init_popcount_bithack( node_filter : NodeFilter, cgra : MRRG, design : Design, vars : Modeler, solver : Solver) -> Term: def _build_grouped_mask(k, n): ''' build_grouped_mask :: int -> int -> Term returns the unique int m of length n that matches the following RE ((0{0,k} 1{k}) | (1{0,k})) (0{k} 1{k})* ''' m = 0 for i in range(k): m |= 1 << i c = 2*k while c < n: m |= m << c c *= 2 return solver.TheoryConst(solver.BitVec(n), m) def _is_power_of_2(x : int) -> bool: return x & (x - 1) == 0 def _floor_log2(x : int) -> int: return x.bit_length() - 1 def _prev_power_of_2(x : int) -> int: return 1 << _floor_log2(x - 1) def _next_power_of_2(x : int) -> int: return 1 << x.bit_length() constraints = [] vs = [vars[n, v] for n in cgra.all_nodes if node_filter(n) for v in design.values] width = len(vs) # build a bitvector from the concanation of bits bv = vars.anonymous_var(solver.BitVec(width)) for idx,v in enumerate(vs): constraints.append(bv[idx] == v) # Boolector can't handle lshr on non power of 2, so zero extend if solver.solver_name == 'Boolector' and not _is_power_of_2(width): l = _next_power_of_2(width) bv = solver.Concat(solver.TheoryConst(solver.BitVec(l - width), 0), bv) width = bv.sort.width pop_count = vars.init_var(node_filter, bv.sort) if width <= 1: constraints.append(pop_count == bv) return solver.And(constraints) elif width == 2: constraints.append(pop_count == (bv & 1) + (bv >> 1)) return solver.And(constraints) max_shift = _prev_power_of_2(width) def _mask_shift_add(x, shift): mask = _build_grouped_mask(shift, width) return (x & mask) + ((x >> shift) & mask) shifts = it.takewhile(lambda n : n <= max_shift, (1 << i for i in it.count())) x = ft.reduce(_mask_shift_add, shifts, bv) constraints.append(pop_count == x) return solver.And(constraints)