예제 #1
0
파일: mapper.py 프로젝트: sillycross/peak
def rr_from_solver(solver, irmapper):
    im = irmapper
    am = irmapper.archmapper

    arch_input_form_val = log2(int(solved_to_bv(am.input_form_var, solver)))
    ib_val = log2(int(solved_to_bv(im.ib_var, solver)))
    ob_val = log2(int(solved_to_bv(im.ob_var, solver)))

    ibinding = im.input_bindings[arch_input_form_val][ib_val]
    obinding = im.output_bindings[ob_val]

    #extract, simplify, and convert constants to BV in the input binding
    bv_ibinding = []
    for ir_path, arch_path in ibinding:
        if ir_path is Unbound:
            var = am.input_varmap[arch_path]
            bv_val = solved_to_bv(var, solver)
            ir_path = bv_val
        bv_ibinding.append((ir_path, arch_path))

    bv_ibinding = rebind_binding(bv_ibinding, family.PyFamily())
    arch_input_aadt_t = _input_aadt_t(am.peak_fc, family.PyFamily())

    bv_ibinding = SimplifyBinding()(arch_input_aadt_t, bv_ibinding)
    bv_ibinding = _strip_aadt(bv_ibinding)
    return RewriteRule(bv_ibinding, obinding, im.peak_fc, am.peak_fc)
예제 #2
0
def test_automapper():
    IR = gen_SmallIR(8)
    arch_fc = PE_fc
    arch_bv = arch_fc(family.PyFamily())
    arch_mapper = ArchMapper(arch_fc)
    expect_found = ('Add', 'Sub', 'And', 'Nand', 'Or', 'Nor', 'Not', 'Neg')
    expect_not_found = ('Mul', 'Shftr', 'Shftl', 'Not', 'Neg')
    for ir_name, ir_fc in IR.instructions.items():
        ir_mapper = arch_mapper.process_ir_instruction(ir_fc)
        rewrite_rule = ir_mapper.solve('z3')
        if rewrite_rule is None:
            assert ir_name in expect_not_found
            continue
        assert ir_name in expect_found
        #verify the mapping works
        counter_example = rewrite_rule.verify()
        assert counter_example is None
        ir_bv = ir_fc(family.PyFamily())
        for _ in range(num_test_vectors):
            ir_vals = {
                path: BitVector.random(8)
                for path in rewrite_rule.ir_bounded
            }
            ir_inputs = rewrite_rule.build_ir_input(ir_vals, family.PyFamily())
            arch_inputs = rewrite_rule.build_arch_input(
                ir_vals, family.PyFamily())
            assert ir_bv()(**ir_inputs) == arch_bv()(**arch_inputs)
예제 #3
0
파일: utils.py 프로젝트: sillycross/peak
def rebind_value(val, _family):
    if isinstance(val, family.PyFamily().BitVector):
        return _family.BitVector[val.size](val.value)
    elif isinstance(val, family.PyFamily().Bit):
        return _family.Bit(val)
    elif isinstance(val, family.SMTFamily().BitVector):
        if not val._value_.is_constant():
            raise ValueError("Cannot convert non-const SMT var to Py")
        return _family.BitVector[val.size](val._value_.constant_value())
    elif isinstance(val, family.SMTFamily().Bit):
        if not val._value_.is_constant():
            raise ValueError("Cannot convert non-const SMT var to Py")
        return _family.Bit(val._value_.constant_value())
    else:
        raise ValueError(f"Cannot rebind value: {val}")
예제 #4
0
def test_early_out_outputs():
    @family_closure
    def IR_fc(family):
        Data = family.BitVector[16]

        @family.assemble(locals(), globals())
        class IR(Peak):
            @name_outputs(out=Data)
            def __call__(self, in_: Data):
                return in_

        return IR

    @family_closure
    def Arch_fc(family):
        Data = family.BitVector[16]
        Bit = family.Bit

        @family.assemble(locals(), globals())
        class Arch(Peak):
            @name_outputs(out=Bit)
            def __call__(self, in_: Data):
                return in_[0]

        return Arch

    arch_fc = Arch_fc
    arch_bv = arch_fc(family.PyFamily())
    arch_mapper = ArchMapper(arch_fc)
    ir_fc = IR_fc
    ir_mapper = arch_mapper.process_ir_instruction(ir_fc)
    rr = ir_mapper.solve('z3')
    assert rr is None
    assert not ir_mapper.has_bindings
예제 #5
0
def test_assemble():
    @family_closure
    def PE_fc(family):
        Bit = family.Bit

        @family.assemble(locals(), globals())
        class PESimple(Peak, typecheck=True):
            def __call__(self, in0: Bit, in1: Bit) -> Bit:
                return in0 & in1

        return PESimple

    #verify BV works
    PE_bv = PE_fc(family.PyFamily())
    vals = [Bit(0), Bit(1)]
    for i0, i1 in itertools.product(vals, vals):
        assert PE_bv()(i0, i1) == i0 & i1

    #verify SMT works
    PE_smt = PE_fc(family.SMTFamily())
    vals = [SMTBit(0), SMTBit(1), SMTBit(), SMTBit()]
    for i0, i1 in itertools.product(vals, vals):
        assert PE_smt()(i0, i1) == i0 & i1

    #verify magma works
    PE_magma = PE_fc(family.MagmaFamily())
    tester = fault.Tester(PE_magma)
    vals = [0, 1]
    for i0, i1 in itertools.product(vals, vals):
        tester.circuit.in0 = i0
        tester.circuit.in1 = i1
        tester.eval()
        tester.circuit.O.expect(i0 & i1)
    tester.compile_and_run("verilator", flags=["-Wno-fatal"])
예제 #6
0
def test_composition():
    PE_magma = PE_fc(family.MagmaFamily())
    PE_py = PE_fc(family.PyFamily())()
    tester = fault.Tester(PE_magma)
    Op = Inst.op0
    assert Op is Inst.op1
    asm = Assembler(Inst)
    for op0, op1, choice, in0, in1 in itertools.product(
            Inst.op0.enumerate(),
            Inst.op1.enumerate(),
        (Bit(0), Bit(1)),
            range(4),
            range(4),
    ):
        in0 = BitVector[16](in0)
        in1 = BitVector[16](in1)
        inst = Inst(op0=op0, op1=op1, choice=choice)
        gold = PE_py(inst=inst, data0=in0, data1=in1)

        tester.circuit.inst = asm.assemble(inst)
        tester.circuit.data0 = in0
        tester.circuit.data1 = in1
        tester.eval()
        tester.circuit.O.expect(gold)
    tester.compile_and_run("verilator", flags=["-Wno-fatal"])
예제 #7
0
def run_constraint_test(ir_fc, constraints, solved):
    arch_fc = PE_fc
    arch_bv = arch_fc(family.PyFamily())
    arch_mapper = ArchMapper(arch_fc, path_constraints=constraints)
    ir_mapper = arch_mapper.process_ir_instruction(ir_fc)
    assert ir_mapper.has_bindings
    rr = ir_mapper.solve('z3')
    if rr is None:
        assert not solved
    else:
        assert solved
예제 #8
0
def test_enum():
    class Op(Enum):
        And = 1
        Or = 2

    @family_closure
    def PE_fc(family):

        Bit = family.Bit

        @family.assemble(locals(), globals())
        class PE_Enum(Peak):
            def __call__(self, op: Const(Op), in0: Bit, in1: Bit) -> Bit:
                if op == Op.And:
                    return in0 & in1
                else:  #op == Op.Or
                    return in0 | in1

        return PE_Enum

    # verify BV works
    PE_bv = PE_fc(family.PyFamily())
    vals = [Bit(0), Bit(1)]
    for op in Op.enumerate():
        for i0, i1 in itertools.product(vals, vals):
            res = PE_bv()(op, i0, i1)
            gold = (i0 & i1) if (op is Op.And) else (i0 | i1)
            assert res == gold

    # verify BV works
    PE_smt = PE_fc(family.SMTFamily())
    Op_aadt = AssembledADT[Op, Assembler, SMTBitVector]
    vals = [SMTBit(0), SMTBit(1), SMTBit(), SMTBit()]
    for op in Op.enumerate():
        op = Op_aadt(op)
        for i0, i1 in itertools.product(vals, vals):
            res = PE_smt()(op, i0, i1)
            gold = (i0 & i1) if (op is Op.And) else (i0 | i1)
            assert res == gold

    # verify magma works
    asm = Assembler(Op)
    PE_magma = PE_fc(family.MagmaFamily())
    tester = fault.Tester(PE_magma)
    vals = [0, 1]
    for op in (Op.And, Op.Or):
        for i0, i1 in itertools.product(vals, vals):
            gold = (i0 & i1) if (op is Op.And) else (i0 | i1)
            tester.circuit.op = int(asm.assemble(op))
            tester.circuit.in0 = i0
            tester.circuit.in1 = i1
            tester.eval()
            tester.circuit.O.expect(gold)
    tester.compile_and_run("verilator", flags=["-Wno-fatal"])
예제 #9
0
def test_wrap_with_disassembler():
    class HashableDict(dict):
        def __hash__(self):
            return hash(tuple(sorted(self.keys())))

    PE_magma = PE_fc(family.MagmaFamily())
    instr_type = PE_fc(family.PyFamily()).input_t.field_dict['inst']
    asm = Assembler(instr_type)
    instr_magma_type = type(PE_magma.interface.ports['inst'])
    PE_wrapped = wrap_with_disassembler(PE_magma, asm.disassemble, asm.width,
                                        HashableDict(asm.layout),
                                        instr_magma_type)
예제 #10
0
def sram_stub(
        mem_depth=4,
        word_width=16,
        fetch_width=4,
        family=family.PyFamily()):

    data_width = word_width * fetch_width
    num_bits = mem_depth * data_width
    addr_width = int(log2(mem_depth))

    @family_closure
    def modules_fc(family):
        BitVector = family.Unsigned
        Bit = family.Bit
        WideData = family.Unsigned[data_width]

        @family.assemble(locals(), globals())
        class SRAMStub():
            def __init__(self):
                self.mem: BitVector[num_bits] = BitVector[num_bits](0)

            @name_outputs(data_out=WideData)
            def __call__(self,
                         wen: Bit = Bit(0),
                         cen: Bit = Bit(0),
                         addr: BitVector[addr_width] = BitVector[addr_width](0),
                         data_in: WideData = WideData(0)
                         ) -> (WideData):

                # print("wen: ", wen, " cen: ", cen, " data_in ", data_in, " addr: ", addr)
                # print("mem: ", self.mem)
                if cen & wen:
                    # print("set slice addr ", addr)
                    result = set_slice(self.mem, addr, data_width, data_in)
                    self.mem = result
                    # print("mem after set slice ", self.mem)

                if cen & ~wen:
                    # print("getting slice")
                    # print("get slice mem ", self.mem)
                    data_out = get_slice(self.mem, addr, data_width)
                else:
                    data_out = WideData(0)

                # print("mem: ", self.mem)
                # print("data out: ", data_out)
                return data_out

        return SRAMStub

    return modules_fc
예제 #11
0
def test_const():

    #Testing out something like coreir const
    @family_closure
    def IR_fc(family):
        Data = family.BitVector[16]

        @family.assemble(locals(), globals())
        class IR(Peak):
            @name_outputs(out=Data)
            def __call__(self, const_value: Const(Data)):
                return const_value

        return IR

    @family_closure
    def Arch_fc(family):
        Data = family.BitVector[16]

        class Op(Enum):
            add = 1
            const = 2

        class Inst(Product):
            op = Op
            imm = Data

        @family.assemble(locals(), globals())
        class Arch(Peak):
            @name_outputs(out=Data)
            def __call__(self, inst: Const(Inst), in0: Data, in1: Data):
                if inst.op == Op.add:
                    return in0 + in1
                else:  #inst.op == Op.const
                    return inst.imm

        return Arch

    arch_fc = Arch_fc
    arch_bv = arch_fc(family.PyFamily())
    arch_mapper = ArchMapper(arch_fc)
    ir_fc = IR_fc
    ir_mapper = arch_mapper.process_ir_instruction(ir_fc)
    rr = ir_mapper.solve('z3')
    assert rr is not None
    assert (('const_value', ), ('inst', 'imm')) in rr.ibinding
예제 #12
0
                # print("mem: ", self.mem)
                # print("data out: ", data_out)
                return data_out

        return SRAMStub

    return modules_fc


if __name__ == "__main__":
    mem_depth = 4
    data_width = 16
    fetch_width = 4
    addr_width = int(log2(mem_depth))

    py_fam = family.PyFamily()
    sram_py = sram_stub(mem_depth, data_width, fetch_width, py_fam)
    sram_py_inst = sram_py(family=py_fam)()

    sram_magma = sram_stub(mem_depth, data_width, fetch_width, family=family.MagmaFamily())
    sram_magma_defn = sram_magma(family=family.MagmaFamily())
    tester = fault.Tester(sram_magma_defn, sram_magma_defn.CLK)

    model_sram = SRAMModel(data_width, fetch_width, mem_depth, 1)

    rand.seed(0)

    x = 0
    for i in range(16):
        wen = 1 - (i % 2)  # rand.randint(0, 1)
        cen = 1  # rand.randint(0, 1)
예제 #13
0
def check_families(PE_fc):
    PE_bv = PE_fc(f.PyFamily())
    PE_smt = PE_fc(f.SMTFamily())
    PE_magma = PE_fc(f.MagmaFamily())
예제 #14
0
def test_custom_rr():

    #This is like a CoreIR Add
    @family_closure
    def coreir_add_fc(family):
        Data = family.BitVector[16]

        @family.assemble(locals(), globals())
        class IR(Peak):
            @name_outputs(out=Data)
            def __call__(self, in0: Data, in1: Data):
                return in0 + in1

        return IR

    #Simple PE that can only add or subtract
    @family_closure
    def PE_fc(family):
        Data = family.BitVector[16]

        class Inst(Product):
            class Op(Enum):
                add = 1
                sub = 2

            sel = family.Bit

        @family.assemble(locals(), globals())
        class Arch(Peak):
            def __call__(self, inst: Const(Inst), a: Data,
                         b: Data) -> (Data, Data):
                if inst.Op == Inst.Op.add:
                    ret = a + b
                else:  #inst == Inst.sub
                    ret = a - b
                if inst.sel:
                    return ret, ret
                else:
                    return ~ret, ~ret

        return Arch, Inst

    Inst_bv = PE_fc(family.PyFamily())[1]
    Inst_adt = AssembledADT[Inst_bv, Assembler, BitVector]

    ir_fc = coreir_add_fc
    arch_fc = lambda f: PE_fc(f)[0]  #Only return peak class
    output_binding = [(("out", ), (0, ))]

    #Test correct rewrite rule
    input_binding = [
        (("in0", ), ("a", )),
        (("in1", ), ("b", )),
        (Inst_adt.Op(Inst_bv.Op.add)._value_, (
            "inst",
            "Op",
        )),
        (Bit(1), (
            "inst",
            "sel",
        )),
    ]
    rr = RewriteRule(input_binding, output_binding, ir_fc, arch_fc)
    assert rr.verify() is None

    #Test incorrect rewrite rule
    input_binding = [
        (("in0", ), ("a", )),
        (("in1", ), ("b", )),
        (Inst_adt.Op(Inst_bv.Op.sub)._value_, (
            "inst",
            "Op",
        )),
        (Bit(0), (
            "inst",
            "sel",
        )),
    ]
    rr = RewriteRule(input_binding, output_binding, ir_fc, arch_fc)
    counter_example = rr.verify()
    assert counter_example is not None

    #Show that counter example is in fact a counter example
    ir_vals = counter_example
    ir_inputs = rr.build_ir_input(ir_vals, family.PyFamily())
    arch_inputs = rr.build_arch_input(ir_vals, family.PyFamily())
    ir_bv = ir_fc(family.PyFamily())
    arch_bv = arch_fc(family.PyFamily())
    assert ir_bv()(**ir_inputs) != arch_bv()(**arch_inputs)[0]