def _fresh_output(self): # Change bit level names. outputs = dict(self.aigbv.output_map) relabels = {n: cmn._fresh() for n in outputs[self.output]} aig = self.aigbv.aig['o', relabels] circ = attr.evolve(self.aigbv, aig=aig, output_map=frozenset([(self.output, aig.outputs)])) # Change word level name. return type(self)(circ['o', {self.output: cmn._fresh()}])
def atom(wordlen: int, val: Val, signed: bool = True) -> Expr: output = cmn._fresh() if val is None: val = cmn._fresh() if isinstance(val, str): aig = cmn.identity_gate(wordlen, val, output) else: aig = cmn.source(wordlen, val, output, signed) return (SignedBVExpr if signed else UnsignedBVExpr)(aig)
def concat(self, other): combiner = cmn.combine_gate( output=cmn._fresh(), left_wordlen=self.size, left=self.output, right_wordlen=other.size, right=other.output, ) circ = self.aigbv | other.aigbv return type(self)(circ >> combiner)
def __or__(self, other): assert not self.outputs & other.outputs assert not self.latches & other.latches shared_inputs = self.inputs & other.inputs input_map = dict(self.input_map) if shared_inputs: relabels1 = {n: common._fresh() for n in shared_inputs} relabels2 = {n: common._fresh() for n in shared_inputs} self, other = self['i', relabels1], other['i', relabels2] circ = AIGBV(aig=self.aig | other.aig, input_map=self.input_map | other.input_map, output_map=self.output_map | other.output_map, latch_map=self.latch_map | other.latch_map) if shared_inputs: for orig in shared_inputs: new1, new2 = relabels1[orig], relabels2[orig] circ <<= common.tee(len(input_map[orig]), {orig: [new1, new2]}) return circ
def _binary_gate(gate, expr1, expr2, same_circ=None): if isinstance(expr2, int): expr2 = atom(expr1.size, expr2, signed=isinstance(expr1, SignedBVExpr)) assert expr1.size == expr2.size if expr1.aigbv == expr2.aigbv and same_circ is not None: return type(expr1)(same_circ(expr1)) elif expr1.aigbv.aig.outputs & expr2.aigbv.aig.outputs: expr2 = expr2._fresh_output() circ3 = expr1.aigbv | expr2.aigbv circ3 >>= gate(wordlen=expr1.size, output=cmn._fresh(), left=expr1.output, right=expr2.output) return type(expr1)(aigbv=circ3)
def repeat(self, times): # TODO: support size != 1 via self concatenation. assert self.size == 1 repeater = cmn.repeat(times, self.output, cmn._fresh()) return type(self)(self.aigbv >> repeater)
def _indexer(idx): return cmn.index_gate(self.size, idx, self.output, cmn._fresh())
def _unary_gate(gate, expr): circ = gate(expr.size, input=expr.output, output=cmn._fresh()) return type(expr)(aigbv=expr.aigbv >> circ)