def synthesize(opc): syn = Synthesizer() syn.addInput(BitVecVar('r0', 8)) syn.addInput(BitVecVar('r1', 8)) syn.addInput(BitVecVar('opcode', 2)) r0 = syn.inp('r0') r1 = syn.inp('r1') opcode = syn.inp('opcode') ra = Choice('ra', None, [r0, r1]) add_r = Add(r0, ra) sub_r = Sub(r0, ra) r0_next = Choice('r0_next', None, [add_r, sub_r]) syn.addOutput('r0', r0_next, Synthesizer.BITVEC) syn.debug(vb=2, lf=sys.stdout, uc=True) cnst = Equal(opcode, BitVecVal(opc, 2)) r = syn.synthesize(['r0'], [cnst], alu_sim) print str(r[0]) print '-' * 40
def synthesize(output_state, fsm_state, log, output, verbosity, unsat_core): syn = Synthesizer() xmem = createInputs(syn) # common signals. mem_op_bits = ast.Extract(3, 2, xmem.op) rd_en = ast.Equal(mem_op_bits, ast.BitVecVal(1, 2)) wr_en = ast.Equal(mem_op_bits, ast.BitVecVal(2, 2)) # aes. in_aes_range, aes_dataout = modelAES(syn, rd_en, wr_en, xmem) # sha. in_sha_range, sha_dataout = modelSHA(syn, rd_en, wr_en, xmem) # model for the xram. xram_dataout = ast.If(rd_en, ast.ReadMem(xmem.xram, xmem.addrin), ast.BitVecVal(0, 8)) xram = ast.If(ast.And(wr_en, ast.Not(in_aes_range), ast.Not(in_sha_range)), ast.WriteMem(xmem.xram, xmem.addrin, xmem.datain), xmem.xram) # combine everything. xmem.dataout = ast.If(in_aes_range, aes_dataout, ast.If(in_sha_range, sha_dataout, xram_dataout)) xmem.xram = xram syn.addOutput('dataout', xmem.dataout, Synthesizer.BITVEC) syn.addOutput('xram', xmem.xram, Synthesizer.MEM) syn.addOutput('aes_state', xmem.aes_state_next, Synthesizer.BITVEC) syn.addOutput('aes_addr', xmem.aes_addr_next, Synthesizer.BITVEC) syn.addOutput('aes_len', xmem.aes_len_next, Synthesizer.BITVEC) syn.addOutput('aes_ctr', xmem.aes_ctr_next, Synthesizer.BITVEC) syn.addOutput('aes_key0', xmem.aes_key0_next, Synthesizer.BITVEC) syn.addOutput('aes_key1', xmem.aes_key1_next, Synthesizer.BITVEC) syn.addOutput('aes_bytes_processed', xmem.aes_bytes_processed_next, Synthesizer.BITVEC) syn.addOutput('aes_read_data', xmem.aes_read_data_next, Synthesizer.BITVEC) syn.addOutput('aes_enc_data', xmem.aes_enc_data_next, Synthesizer.BITVEC) syn.addOutput('sha_state', xmem.sha_state_next, Synthesizer.BITVEC) syn.addOutput('sha_rdaddr', xmem.sha_rdaddr_next, Synthesizer.BITVEC) syn.addOutput('sha_wraddr', xmem.sha_wraddr_next, Synthesizer.BITVEC) syn.addOutput('sha_len', xmem.sha_len_next, Synthesizer.BITVEC) syn.addOutput('sha_bytes_processed', xmem.sha_bytes_processed_next, Synthesizer.BITVEC) syn.addOutput('sha_read_data', xmem.sha_read_data_next, Synthesizer.BITVEC) syn.addOutput('sha_digest', xmem.sha_digest_next, Synthesizer.BITVEC) if log == 'STDOUT': syn.logfile = sys.stdout elif log: syn.logfile = open(log, 'wt') syn.VERBOSITY = verbosity syn.unsat_core = unsat_core # syn.unsat_core = True aes_state = fsm_state & 0x3 sha_state = (fsm_state & 0xc) >> 2 param = ast.And(ast.Equal(xmem.aes_state, ast.BitVecVal(aes_state, 8)), ast.Equal(xmem.sha_state, ast.BitVecVal(sha_state, 8))) [a] = syn.synthesize([output_state], [param], evalxmm) if output: with open(output, 'wb') as f: pk = Pickler(f, -1) pk.dump(fsm_state) pk.dump(output_state) pk.dump(a) else: print '%s' % output_state print str(a) + '\n'
def synthesize(opcs): syn = Synthesizer() create8051Inputs(syn) ctx = Ctx8051FromSyn(syn) mem_SP = ReadMem(ctx.IRAM, ctx.SP) mem_SP_plus1 = ReadMem(ctx.IRAM, Add(ctx.SP, BitVecVal(1, 8))) mem_SP_minus1 = ReadMem(ctx.IRAM, Sub(ctx.SP, BitVecVal(1, 8))) DPTR = Concat(ctx.DPH, ctx.DPL) PC_plus1 = Add(ctx.PC, BitVecVal(1, 16)) PC_plus2 = Add(ctx.PC, BitVecVal(2, 16)) PC_plus3 = Add(ctx.PC, BitVecVal(3, 16)) PC_rel1 = Add( Choice('PC_rel1_base', ctx.op0, [ctx.PC, PC_plus1, PC_plus2, PC_plus3]), SignExt(ctx.op1, 8)) PC_rel2 = Add( Choice('PC_rel2_base', ctx.op0, [ctx.PC, PC_plus1, PC_plus2, PC_plus3]), SignExt(ctx.op2, 8)) PC_ajmp = Concat( Extract(15, 11, Choice('ajmp', ctx.op0, [ctx.PC, PC_plus2])), ChooseConsecBits('ajmp_3bits', 3, ctx.opcode), ChooseConsecBits('ajmp_8bits', 8, ctx.opcode)) PC_ret1 = Concat(mem_SP_minus1, mem_SP) PC_ret2 = Concat(mem_SP, mem_SP_plus1) PC_ret3 = Concat(mem_SP, mem_SP_minus1) PC_ret4 = Concat(mem_SP_plus1, mem_SP) PC_ret = Choice('ctx.SP_pc', ctx.op0, [PC_ret1, PC_ret2, PC_ret3, PC_ret4]) PC_ljmp = Choice('LJMP_order', ctx.op0, [Concat(ctx.op1, ctx.op2), Concat(ctx.op2, ctx.op1)]) PC_sjmp = Choice('SJMP_relpc', ctx.op0, [PC_rel1, PC_rel2]) jb_bitaddr = Choice('jb_bit_addr_choice', ctx.op0, [ctx.op1, ctx.op2]) jb_bit = ctx.readBit(jb_bitaddr) PC_jb_taken = Choice('PC_jb_rel', ctx.op0, [PC_rel1, PC_rel2]) PC_jb_seq = Choice('PC_jb_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_jb = If( Equal( jb_bit, Choice('jb_polarity', ctx.op0, [BitVecVal(1, 1), BitVecVal(0, 1)])), PC_jb_taken, PC_jb_seq) PC_jc_taken = Choice('PC_jc_rel', ctx.op0, [PC_rel1, PC_rel2]) PC_jc_seq = Choice('PC_jc_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_jc = If( Equal( ctx.CY(), Choice('jc_polarity', ctx.op0, [BitVecVal(1, 1), BitVecVal(0, 1)])), PC_jc_taken, PC_jc_seq) PC_jz_taken = Choice('PC_jz_rel', ctx.op0, [PC_rel1, PC_rel2]) PC_jz_seq = Choice('PC_jz_seq', ctx.op0, [PC_plus2, PC_plus3]) ACC_zero = Equal(ctx.ACC, BitVecVal(0, 8)) ACC_not_zero = Not(ACC_zero) PC_jz = If(Choice('jz_polarity', ctx.op0, [ACC_zero, ACC_not_zero]), PC_jz_taken, PC_jz_seq) PC_jmp = Add(DPTR, ZeroExt(ctx.ACC, 8)) cjne_src1 = Choice( 'cjne_src1', ctx.op0, [ctx.ACC, ReadMem(ctx.IRAM, ctx.Rx(0)), ReadMem(ctx.IRAM, ctx.Rx(1))] + ctx.Rxs()) cjne_src2 = Choice('cjne_src2', ctx.op0, [ ctx.op1, ctx.op2, ctx.readDirect(Choice('cjne_iram_addr', ctx.op0, [ctx.op1, ctx.op2])) ]) cjne_taken = Not(Equal(cjne_src1, cjne_src2)) PC_cjne_taken = Choice('PC_cjne_taken', ctx.op0, [PC_rel1, PC_rel2]) PC_cjne_seq = Choice('PC_cjne_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_cjne = If(cjne_taken, PC_cjne_taken, PC_cjne_seq) djnz_src = Choice( 'djnz_src', ctx.op0, [ctx.readDirect(Choice('djnz_iram_src', ctx.op0, [ctx.op1, ctx.op2])) ] + ctx.Rxs()) djnz_taken = Not(Equal(djnz_src, BitVecVal(1, 8))) PC_djnz_taken = Choice('PC_djnz_taken', ctx.op0, [PC_rel1, PC_rel2]) PC_djnz_seq = Choice('PC_djnz_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_djnz = If(djnz_taken, PC_djnz_taken, PC_djnz_seq) nextPC = Choice('nextPC', ctx.op0, [PC_plus1, PC_plus2, PC_plus3]) #PC_ajmp, PC_ret, PC_ljmp, PC_sjmp, PC_jb, #PC_jc, PC_jz, PC_jmp, PC_cjne, PC_djnz]) # IMM1 = ctx.op1 # IRAM_MOV_AT_R0 = WriteMem(ctx.IRAM, Rx[0], IMM1) # syn.addOutput('IRAM', IRAM_MOV_AT_R0, Synthesizer.MEM) # INC_SRC1_INDIR_ADDR = Choice('INC_SRC1_INDIR', ctx.op0, [Rx[0], Rx[1]]) # INC_SRC1_INDIR = ReadMem(ctx.IRAM, INC_SRC1_INDIR_ADDR) ctxNOP = ctx.clone() ctxNOP.PC = nextPC # SP can be incremented, decrement or stay the same ctxNOP.SP = Choice( 'SP_CALL', ctx.op0, [ctx.SP, Add(ctx.SP, BitVecVal(2, 8)), Sub(ctx.SP, BitVecVal(2, 8))]) # SRC2 for instructions which modify accumulator. ACC_SRC2_DIR_ADDR = Choice('ACC_SRC2_DIR_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) ACC_SRC2_DIR = ctx.readDirect(ACC_SRC2_DIR_ADDR) ACC_SRC2_INDIR_ADDR = Choice('ACC_SRC2_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) ACC_SRC2_INDIR = ReadMem(ctx.IRAM, ACC_SRC2_INDIR_ADDR) SRC2_IMM = Choice('SRC2_IMM', ctx.op0, [ctx.op1, ctx.op2]) ACC_SRC2 = Choice('ACC_SRC2', ctx.op0, [ACC_SRC2_DIR, ACC_SRC2_INDIR, SRC2_IMM]) ACC_ROM_OFFSET = Choice('ACC_ROM_OFFSET', ctx.op0, [DPTR, ctx.PC, PC_plus1, PC_plus2, PC_plus3]) # Instructions which modify the accumulator. ACC_RR = RotateRight(ctx.ACC) ACC_RRC = Extract(8, 1, RotateRight(Concat(ctx.ACC, ctx.CY()))) ACC_RL = RotateLeft(ctx.ACC) ACC_RLC = Extract(7, 0, RotateLeft(Concat(ctx.CY(), ctx.ACC))) ACC_INC = Add(ctx.ACC, BitVecVal(1, 8)) ACC_DEC = Sub(ctx.ACC, BitVecVal(1, 8)) ACC_ADD = Add(ctx.ACC, ACC_SRC2) ACC_ADDC = Add(ctx.ACC, Add(ACC_SRC2, ZeroExt(ctx.CY(), 7))) ACC_ORL = BVOr(ctx.ACC, ACC_SRC2) ACC_ANL = BVAnd(ctx.ACC, ACC_SRC2) ACC_XRL = BVXor(ctx.ACC, ACC_SRC2) ACC_MOV = ACC_SRC2 ACC_CPL = Complement(ctx.ACC) ACC_ROM = ReadMem(ctx.ROM, Add(ZeroExt(ctx.ACC, 8), ACC_ROM_OFFSET)) # final acc value. ctxACC = ctxNOP.clone() ctxACC.ACC = Choice('ACC_RES', ctx.op0, [ ACC_RR, ACC_RL, ACC_RRC, ACC_RLC, ACC_INC, ACC_DEC, ACC_ADD, ACC_ADDC, ACC_ORL, ACC_ANL, ACC_XRL, ACC_MOV, ACC_ROM ]) # compute the CY/AC/OV flags ALU_CY_IN = Choice('ALU_CY_IN', ctx.op0, [ctx.CY(), BitVecVal(0, 1)]) ALU_SRC1 = ctx.ACC ALU_SRC1_LO = Extract(3, 0, ALU_SRC1) ALU_SRC1_HI = Extract(7, 4, ALU_SRC1) ALU_SRC2 = ACC_SRC2 ALU_SRC2_LO = Extract(3, 0, ALU_SRC2) ALU_SRC2_HI = Extract(7, 4, ALU_SRC2) ALU_AC = Extract( 4, 4, Add(ZeroExt(ALU_SRC1_LO, 1), Add(ZeroExt(ALU_SRC2_LO, 1), ZeroExt(ALU_CY_IN, 4)))) ALU_SRC1_SEXT = SignExt(ALU_SRC1, 1) ALU_SRC2_SEXT = SignExt(ALU_SRC2, 1) ALU_SRC1_ZEXT = ZeroExt(ALU_SRC1, 1) ALU_SRC2_ZEXT = ZeroExt(ALU_SRC2, 1) ALU_SRC1_FOR_CY = Choice('ALU_SRC_FOR_CY', ctx.op0, [ALU_SRC1_SEXT, ALU_SRC1_ZEXT]) ALU_SRC2_FOR_CY = Choice('ALU_SRC_FOR_CY', ctx.op0, [ALU_SRC2_SEXT, ALU_SRC2_ZEXT]) ALU_CY = Extract( 8, 8, Add(ALU_SRC1_FOR_CY, Add(ALU_SRC2_FOR_CY, ZeroExt(ALU_CY_IN, 8)))) ALU_SRC1_FOR_OV = Choice('ALU_SRC_FOR_OV', ctx.op0, [ALU_SRC1_SEXT, ALU_SRC1_ZEXT]) ALU_SRC2_FOR_OV = Choice('ALU_SRC_FOR_OV', ctx.op0, [ALU_SRC2_SEXT, ALU_SRC2_ZEXT]) ALU_OV_CY = Extract( 8, 8, Add(ALU_SRC2_FOR_OV, Add(ALU_SRC1_FOR_OV, ZeroExt(ALU_CY_IN, 8)))) ALU_OV = If(Equal(ALU_OV_CY, Extract(7, 7, ctxACC.ACC)), BitVecVal(0, 1), BitVecVal(1, 1)) ACC_CY = Choice( 'ACC_CY', ctx.op0, [ctx.CY(), Extract(0, 0, ctx.ACC), Extract(7, 7, ctx.ACC), ALU_CY]) ACC_AC = Choice('ACC_AC', ctx.op0, [ctx.AC(), ALU_AC]) ACC_OV = Choice('ACC_OV', ctx.op0, [ctx.OV(), ALU_OV]) ctxACC.PSW = Concat(ACC_CY, ACC_AC, Extract(5, 3, ctx.PSW), ACC_OV, Extract(1, 0, ctx.PSW)) # multiply and divide. ctxDIV = ctxNOP.clone() ctxDIV.ACC = If(Equal(ctx.B, BitVecVal(0, 8)), BitVecVal(0xFF, 8), BVDiv(ctx.ACC, ctx.B)) ctxDIV.B = If(Equal(ctx.B, BitVecVal(0, 8)), ctx.ACC, BVRem(ctx.ACC, ctx.B)) DIV_OV = If(Equal(ctx.B, BitVecVal(0, 8)), BitVecVal(1, 1), BitVecVal(0, 1)) ctxDIV.PSW = Concat(BitVecVal(0, 1), Extract(6, 3, ctx.PSW), DIV_OV, Extract(1, 0, ctx.PSW)) ctxMUL = ctxNOP.clone() MUL_RESULT = BVMul(ZeroExt(ctx.ACC, 8), ZeroExt(ctx.B, 8)) ctxMUL.ACC = Extract(7, 0, MUL_RESULT) ctxMUL.B = Extract(15, 8, MUL_RESULT) MUL_OV = If(Not(Equal(ctxMUL.B, BitVecVal(0, 8))), BitVecVal(1, 1), BitVecVal(0, 1)) ctxMUL.PSW = Concat(BitVecVal(0, 1), Extract(6, 3, ctx.PSW), MUL_OV, Extract(1, 0, ctx.PSW)) # call type instructions push the PC onto the stack. ctxCALL = ctxNOP.clone() PC_topush = Choice('PC_topush', ctx.op0, [ctx.PC, PC_plus1, PC_plus2, PC_plus3]) PC_topush_lo = Extract(7, 0, PC_topush) PC_topush_hi = Extract(15, 8, PC_topush) PC_topush_0 = Choice('PC_topush_endianess', ctx.op0, [PC_topush_lo, PC_topush_hi]) PC_topush_1 = Choice('PC_topush_endianess', ctx.op0, [PC_topush_hi, PC_topush_lo]) PC_push_addr = Choice('PC_push_addr', ctx.op0, [ctx.SP, Add(ctx.SP, BitVecVal(1, 8))]) ctxCALL.IRAM = WriteMem(WriteMem(ctx.IRAM, PC_push_addr, PC_topush_0), Add(PC_push_addr, BitVecVal(1, 8)), PC_topush_1) # instructions where the result is a direct iram address DIR_SRC1_ADDR = Choice('DIR_SRC1_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) DIR_SRC1 = ctx.readDirect(DIR_SRC1_ADDR) DIR_SRC2_IRAM_ADDR = Choice('DIR_SRC2_IRAM_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) DIR_SRC2_IRAM = ctx.readDirect(DIR_SRC2_IRAM_ADDR) DIR_SRC2_INDIR_ADDR = Choice('DIR_SRC2_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) DIR_SRC2_INDIR = ReadMem(ctx.IRAM, DIR_SRC2_INDIR_ADDR) DIR_SRC2 = Choice( 'DIR_SRC2', ctx.op0, [ctx.op1, ctx.op2, ctx.ACC, DIR_SRC2_IRAM, DIR_SRC2_INDIR]) DIR_INC = Add(DIR_SRC1, BitVecVal(1, 8)) DIR_DEC = Sub(DIR_SRC1, BitVecVal(1, 8)) DIR_ORL = BVOr(DIR_SRC1, DIR_SRC2) DIR_ANL = BVAnd(DIR_SRC1, DIR_SRC2) DIR_XRL = BVXor(DIR_SRC1, DIR_SRC2) DIR_MOV = DIR_SRC2 DIR_RESULT = Choice('DIR_RESULT', ctx.op0, [DIR_INC, DIR_DEC, DIR_ORL, DIR_ANL, DIR_XRL, DIR_MOV]) ctxDIR = ctxNOP.writeDirect(DIR_SRC1_ADDR, DIR_RESULT) # instructions where the result is an indirect iram address SRC1_INDIR_ADDR = Choice('SRC1_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) SRC1_INDIR = ReadMem(ctx.IRAM, SRC1_INDIR_ADDR) SRC2_INDIR = Choice('SRC2_INDIR', ctx.op0, [ctx.op1, ctx.op2]) SRC1_INDIR_INC = Add(SRC1_INDIR, BitVecVal(1, 8)) SRC1_INDIR_DEC = Sub(SRC1_INDIR, BitVecVal(1, 8)) SRC1_INDIR_MOV = SRC2_INDIR SRC1_INDIR_RESULT = Choice( 'SRC1_INDIR_RESULT', ctx.op0, [SRC1_INDIR_INC, SRC1_INDIR_DEC, SRC1_INDIR_MOV]) ctxINDIR = ctxNOP.clone() ctxINDIR.IRAM = WriteMem(ctx.IRAM, SRC1_INDIR_ADDR, SRC1_INDIR_RESULT) # JBC is a weird instruction by itself. # ctxJBC = ctxNOP.writeBit(jb_bitaddr, BitVecVal(0, 1)) # instructions which write to specific bit addressable registers. ctxBIT = ctxNOP.clone() BIT_SRC1_ADDR = Choice('BIT_SRC1_ADDR', ctx.op0, [ctx.op1, ctx.op2]) BIT_SRC1 = ctx.readBit(BIT_SRC1_ADDR) # some instructions write their result to the carry flag; which is also the first operand. CY_ORL = BVOr(ctx.CY(), BIT_SRC1) CY_ORLC = BVOr(ctx.CY(), Complement(BIT_SRC1)) CY_ANL = BVAnd(ctx.CY(), BIT_SRC1) CY_ANLC = BVAnd(ctx.CY(), Complement(BIT_SRC1)) CY_MOV = BIT_SRC1 CY_CPL = Complement(BIT_SRC1) BIT_CNST1 = BitVecVal(1, 1) BIT_CNST0 = BitVecVal(0, 1) BIT_CY = Choice('BIT_CY', ctx.op0, [ CY_ORL, CY_ANL, CY_ORLC, CY_ANLC, CY_MOV, CY_CPL, BIT_CNST1, BIT_CNST0 ]) ctxBIT.PSW = Concat(BIT_CY, Extract(6, 0, ctx.PSW)) WRBIT_CY = ctx.CY() WRBIT_CPL = Complement(BIT_SRC1) WRBIT_DATA = Choice('WRBIT_DATA', ctx.op0, [WRBIT_CY, WRBIT_CPL, BIT_CNST0, BIT_CNST1]) ctxWRBIT = ctxNOP.writeBit(BIT_SRC1_ADDR, WRBIT_DATA) # final result. ctxFINAL = CtxChoice('CTX3', ctx.op0, [ ctxNOP, ctxACC, ctxDIR, ctxINDIR, ctxCALL, ctxBIT, ctxMUL, ctxDIV, ctxWRBIT ]) syn.addOutput('PC', ctxFINAL.PC, Synthesizer.BITVEC) syn.addOutput('ACC', ctxFINAL.ACC, Synthesizer.BITVEC) syn.addOutput('IRAM', ctxFINAL.IRAM, Synthesizer.MEM) syn.addOutput('PSW', ctxFINAL.PSW, Synthesizer.BITVEC) syn.addOutput('SP', ctxFINAL.SP, Synthesizer.BITVEC) syn.addOutput('B', ctxFINAL.B, Synthesizer.BITVEC) syn.debug(4) for opc in opcs: z3._main_ctx = None cnst = Equal(ctx.op0, BitVecVal(opc, 8)) r = syn.synthesize(['PC'], [cnst], eval8051) #r += syn.synthesize(['ACC'], [cnst], eval8051) #r += syn.synthesize(['PSW'], [cnst], eval8051) #r += syn.synthesize(['SP'], [cnst], eval8051) #r += syn.synthesize(['IRAM'], [cnst], eval8051) fmt = '%02x\n' + ('\n'.join(['%s'] * len(r))) + '\n' print fmt % tuple([opc] + r)
def synAES(st): syn = Synthesizer() createInputs(syn) state = syn.inp('state') addr = syn.inp('addr') length = syn.inp('length') num_op_bytes = syn.inp('num_op_bytes') block_ctr = syn.inp('block_ctr') ctr = syn.inp('ctr') key = syn.inp('key') xram = syn.inp('xram') op = syn.inp('op') addr_in = syn.inp('addr_in') data_in = syn.inp('data_in') aesfns = [syn.inp('AES%d' % i) for i in xrange(16)] addrlist = [BitVecVal(x, 16) for x in [0xFF00, 0xFF01, 0xFF02, 0xFF04, 0xFF10, 0xFF20]] init_state = BitVecVal(0, 1) op_state = BitVecVal(1, 1) in_init_state = Equal(state, init_state) REG_STATE_ADDR = Choice('REG_STATE_ADDR', state, addrlist) REG_START_ADDR = Choice('REG_START_ADDR', state, addrlist) REG_ADDR_ADDR = Choice('REG_ADDR_ADDR', state, addrlist) REG_LEN_ADDR = Choice('REG_LEN_ADDR', state, addrlist) REG_CTR_ADDR = Choice('REG_CTR_ADDR', state, addrlist) REG_KEY_ADDR = Choice('REG_KEY_ADDR', state, addrlist) nop = Equal(op, BitVecVal(0, 2)) rd = Equal(op, BitVecVal(1, 2)) wr = And(in_init_state, Equal(op, BitVecVal(2, 2))) start_out = write1byteReg(wr, addr_in, BitVecVal(0,8), REG_START_ADDR, data_in) addr_out = write2byteReg(wr, addr_in, addr, REG_ADDR_ADDR, data_in) length_out = write2byteReg(wr, addr_in, length, REG_LEN_ADDR, data_in) ctr_out = write16byteReg(wr, addr_in, ctr, REG_CTR_ADDR, data_in) key_out = write16byteReg(wr, addr_in, key, REG_KEY_ADDR, data_in) start = And(wr, Equal(Extract(0, 0, start_out), BitVecVal(1, 1))) num_op_bytes_out = If(in_init_state, If(start, BitVecVal(0, 16), num_op_bytes), Add(num_op_bytes, BitVecVal(16, 16))) more_blocks = ULT(num_op_bytes_out, length) block_ctr_out = If(in_init_state, If(start, BitVecVal(0, 16), block_ctr), If(more_blocks, Add(block_ctr, BitVecVal(16, 16)), block_ctr)) init_state_next = If(start, op_state, init_state) op_state_next = If(more_blocks, op_state, init_state) state_next = If(in_init_state, init_state_next, op_state_next) aes_args = getAESArgs(ctr, key, xram, addr, block_ctr) aes_xram = getUpdatedXram(xram, addr, block_ctr, aes_args, aesfns) xram_out = If(in_init_state, xram, aes_xram) syn.addOutput('addr', addr_out, Synthesizer.BITVEC) syn.addOutput('length', length_out, Synthesizer.BITVEC) syn.addOutput('ctr', ctr_out, Synthesizer.BITVEC) syn.addOutput('key', key_out, Synthesizer.BITVEC) syn.addOutput('num_op_bytes', num_op_bytes_out, Synthesizer.BITVEC) syn.addOutput('block_ctr', block_ctr_out, Synthesizer.BITVEC) syn.addOutput('state', state_next, Synthesizer.BITVEC) syn.addOutput('xram', xram_out, Synthesizer.MEM) cnsts = [ Equal(state, BitVecVal(st, 1)), And(UGT(addr_in, BitVecVal(0xFF00-1, 16)), ULT(addr_in, BitVecVal(0xFF40, 16))) ] outputs = ['addr', 'length', 'ctr', 'key', 'num_op_bytes', 'block_ctr', 'state'] # syn.debug() return syn.synthesize(['addr'], cnsts, evalAES)
def synthesize(opc, regs, logfilename, outputfilename, verbosity, unsat_core): syn = Synthesizer() create8051Inputs(syn) ctx = Ctx8051FromSyn(syn) mem_SP = ReadMem(ctx.IRAM, ctx.SP) mem_SP_plus1 = ReadMem(ctx.IRAM, Add(ctx.SP, BitVecVal(1, 8))) mem_SP_minus1 = ReadMem(ctx.IRAM, Sub(ctx.SP, BitVecVal(1, 8))) DPTR = Concat(ctx.DPH, ctx.DPL) PC_plus1 = Add(ctx.PC, BitVecVal(1, 16)) PC_plus2 = Add(ctx.PC, BitVecVal(2, 16)) PC_plus3 = Add(ctx.PC, BitVecVal(3, 16)) PC_rel1 = Add( Choice('PC_rel1_base', ctx.op0, [ctx.PC, PC_plus1, PC_plus2, PC_plus3]), SignExt(ctx.op1, 8)) PC_rel2 = Add( Choice('PC_rel2_base', ctx.op0, [ctx.PC, PC_plus1, PC_plus2, PC_plus3]), SignExt(ctx.op2, 8)) PC_ajmp = Concat( Extract(15, 11, Choice('ajmp', ctx.op0, [ctx.PC, PC_plus2])), ChooseConsecBits('ajmp_3bits', 3, ctx.opcode), ChooseConsecBits('ajmp_8bits', 8, ctx.opcode)) PC_ret1 = Concat(mem_SP_minus1, mem_SP) PC_ret2 = Concat(mem_SP, mem_SP_plus1) PC_ret3 = Concat(mem_SP, mem_SP_minus1) PC_ret4 = Concat(mem_SP_plus1, mem_SP) PC_ret = Choice('ctx.SP_pc', ctx.op0, [PC_ret1, PC_ret2, PC_ret3, PC_ret4]) PC_ljmp = Choice('LJMP_order', ctx.op0, [Concat(ctx.op1, ctx.op2), Concat(ctx.op2, ctx.op1)]) PC_sjmp = Choice('SJMP_relpc', ctx.op0, [PC_rel1, PC_rel2]) jb_bitaddr = Choice('jb_bit_addr_choice', ctx.op0, [ctx.op1, ctx.op2]) jb_bit = ctx.readBit(jb_bitaddr) PC_jb_taken = Choice('PC_jb_rel', ctx.op0, [PC_rel1, PC_rel2]) PC_jb_seq = Choice('PC_jb_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_jb = If( Equal( jb_bit, Choice('jb_polarity', ctx.op0, [BitVecVal(1, 1), BitVecVal(0, 1)])), PC_jb_taken, PC_jb_seq) PC_jc_taken = Choice('PC_jc_rel', ctx.op0, [PC_rel1, PC_rel2]) PC_jc_seq = Choice('PC_jc_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_jc = If( Equal( ctx.CY(), Choice('jc_polarity', ctx.op0, [BitVecVal(1, 1), BitVecVal(0, 1)])), PC_jc_taken, PC_jc_seq) PC_jz_taken = Choice('PC_jz_rel', ctx.op0, [PC_rel1, PC_rel2]) PC_jz_seq = Choice('PC_jz_seq', ctx.op0, [PC_plus2, PC_plus3]) ACC_zero = Equal(ctx.ACC, BitVecVal(0, 8)) ACC_not_zero = Not(ACC_zero) PC_jz = If(Choice('jz_polarity', ctx.op0, [ACC_zero, ACC_not_zero]), PC_jz_taken, PC_jz_seq) PC_jmp = Add(DPTR, ZeroExt(ctx.ACC, 8)) cjne_src1 = Choice( 'cjne_src1', ctx.op0, [ctx.ACC, ReadMem(ctx.IRAM, ctx.Rx(0)), ReadMem(ctx.IRAM, ctx.Rx(1))] + ctx.Rxs()) cjne_src2 = Choice('cjne_src2', ctx.op0, [ ctx.op1, ctx.op2, ctx.readDirect(Choice('cjne_iram_addr', ctx.op0, [ctx.op1, ctx.op2])) ]) cjne_taken = Not(Equal(cjne_src1, cjne_src2)) PC_cjne_taken = Choice('PC_cjne_taken', ctx.op0, [PC_rel1, PC_rel2]) PC_cjne_seq = Choice('PC_cjne_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_cjne = If(cjne_taken, PC_cjne_taken, PC_cjne_seq) djnz_src = Choice( 'djnz_src', ctx.op0, [ctx.readDirect(Choice('djnz_iram_src', ctx.op0, [ctx.op1, ctx.op2])) ] + ctx.Rxs()) djnz_taken = Not(Equal(djnz_src, BitVecVal(1, 8))) PC_djnz_taken = Choice('PC_djnz_taken', ctx.op0, [PC_rel1, PC_rel2]) PC_djnz_seq = Choice('PC_djnz_seq', ctx.op0, [PC_plus2, PC_plus3]) PC_djnz = If(djnz_taken, PC_djnz_taken, PC_djnz_seq) nextPC = Choice('nextPC', ctx.op0, [ PC_plus1, PC_plus2, PC_plus3, PC_ajmp, PC_ret, PC_ljmp, PC_sjmp, PC_jb, PC_jc, PC_jz, PC_jmp, PC_cjne, PC_djnz ]) ctxNOP = ctx.clone() ctxNOP.PC = nextPC # SP can be incremented, decrement or stay the same ctxNOP.SP = Choice( 'SP_CALL', ctx.op0, [ctx.SP, Add(ctx.SP, BitVecVal(2, 8)), Sub(ctx.SP, BitVecVal(2, 8))]) # CJNE sets the carry flag ctxCJNE = ctxNOP.clone() CJNE_CY = If(ULT(cjne_src1, cjne_src2), BitVecVal(1, 1), BitVecVal(0, 1)) ctxCJNE.PSW = Concat(CJNE_CY, Extract(6, 0, ctx.PSW)) # SRC2 for instructions which modify accumulator. ACC_SRC2_DIR_ADDR = Choice('ACC_SRC2_DIR_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) ACC_SRC2_DIR = ctx.readDirect(ACC_SRC2_DIR_ADDR) ACC_SRC2_INDIR_ADDR = Choice('ACC_SRC2_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) ACC_SRC2_INDIR = ReadMem(ctx.IRAM, ACC_SRC2_INDIR_ADDR) SRC2_IMM = Choice('SRC2_IMM', ctx.op0, [ctx.op1, ctx.op2]) ACC_SRC2 = Choice('ACC_SRC2', ctx.op0, [ACC_SRC2_DIR, ACC_SRC2_INDIR, SRC2_IMM]) ACC_ROM_OFFSET = Choice('ACC_ROM_OFFSET', ctx.op0, [DPTR, ctx.PC, PC_plus1, PC_plus2, PC_plus3]) # The decimal adjust instruction. This is a bit of mess. # First, deal with the lower nibble ACC_DA_LO = Extract(3, 0, ctx.ACC) ACC_ADD_6 = Or(Equal(ctx.AC(), BitVecVal(1, 1)), UGT(ACC_DA_LO, BitVecVal(9, 4))) ACC_DA_stage1 = If(ACC_ADD_6, Add(ZeroExt(ctx.ACC, 1), BitVecVal(0x6, 9)), ZeroExt(ctx.ACC, 1)) ACC_DA_CY1 = Extract(8, 8, ACC_DA_stage1) # and then the upper nibble ACC_DA_HI = Extract(7, 4, ACC_DA_stage1) ACC_ADD_60 = Or(Equal(BVOr(ACC_DA_CY1, ctx.CY()), BitVecVal(1, 1)), UGT(ACC_DA_HI, BitVecVal(9, 4))) ACC_DA_stage2 = If(ACC_ADD_60, Add(ACC_DA_stage1, BitVecVal(0x60, 9)), ACC_DA_stage1) ACC_DA = Extract(7, 0, ACC_DA_stage2) ACC_DA_CY2 = Extract(8, 8, ACC_DA_stage2) ACC_DA_CY = BVOr(ACC_DA_CY2, BVOr(ACC_DA_CY1, ctx.CY())) ctxDA = ctxNOP.clone() ctxDA.ACC = ACC_DA ctxDA.PSW = Concat(ACC_DA_CY, Extract(6, 0, ctx.PSW)) # Instructions which modify the accumulator. ACC_RR = RotateRight(ctx.ACC) ACC_RRC = Extract(8, 1, RotateRight(Concat(ctx.ACC, ctx.CY()))) ACC_RL = RotateLeft(ctx.ACC) ACC_RLC = Extract(7, 0, RotateLeft(Concat(ctx.CY(), ctx.ACC))) ACC_INC = Add(ctx.ACC, BitVecVal(1, 8)) ACC_DEC = Sub(ctx.ACC, BitVecVal(1, 8)) ACC_ADD = Add(ctx.ACC, ACC_SRC2) ACC_ADDC = Add(ctx.ACC, Add(ACC_SRC2, ZeroExt(ctx.CY(), 7))) ACC_ORL = BVOr(ctx.ACC, ACC_SRC2) ACC_ANL = BVAnd(ctx.ACC, ACC_SRC2) ACC_XRL = BVXor(ctx.ACC, ACC_SRC2) ACC_SUBB = Add(Sub(ctx.ACC, ACC_SRC2), SignExt(ctx.CY(), 7)) ACC_MOV = ACC_SRC2 ACC_CPL = Complement(ctx.ACC) ACC_CLR = BitVecVal(0, 8) ACC_ROM = ReadMem(ctx.ROM, Add(ZeroExt(ctx.ACC, 8), ACC_ROM_OFFSET)) ACC_SWAP = Concat(Extract(3, 0, ctx.ACC), Extract(7, 4, ctx.ACC)) # final acc value. ctxACC = ctxNOP.clone() ctxACC.ACC = Choice('ACC_RES', ctx.op0, [ ACC_RR, ACC_RL, ACC_RRC, ACC_RLC, ACC_INC, ACC_DEC, ACC_ADD, ACC_ADDC, ACC_ORL, ACC_ANL, ACC_XRL, ACC_MOV, ACC_ROM, ACC_CLR, ACC_SUBB, ACC_SWAP, ACC_CPL ]) # compute the CY/AC/OV flags ALU_CY_IN = Choice('ALU_CY_IN', ctx.op0, [ctx.CY(), BitVecVal(0, 1)]) ALU_SRC1 = ctx.ACC ALU_SRC1_LO = Extract(3, 0, ALU_SRC1) ALU_SRC1_HI = Extract(7, 4, ALU_SRC1) ALU_SRC2 = ACC_SRC2 ALU_SRC2_LO = Extract(3, 0, ALU_SRC2) ALU_SRC2_HI = Extract(7, 4, ALU_SRC2) ALU_CY_5B = Choice( 'ALU_CY_5B', ctx.op0, [ZeroExt(ALU_CY_IN, 4), SignExt(ALU_CY_IN, 4)]) ALU_SRC1_LO_5B = ZeroExt(ALU_SRC1_LO, 1) ALU_SRC2_LO_5B = ZeroExt(ALU_SRC2_LO, 1) ALU_AC_ADD = Extract(4, 4, Add(ALU_SRC1_LO_5B, Add(ALU_SRC2_LO_5B, ALU_CY_5B))) ALU_AC_SUB = If(ULT(ALU_SRC1_LO_5B, Add(ALU_SRC2_LO_5B, ALU_CY_5B)), BitVecVal(1, 1), BitVecVal(0, 1)) ALU_AC = Choice('ALU_AC', ctx.op0, [ALU_AC_ADD, ALU_AC_SUB]) ALU_SRC1_SEXT = SignExt(ALU_SRC1, 1) ALU_SRC2_SEXT = SignExt(ALU_SRC2, 1) ALU_SRC1_ZEXT = ZeroExt(ALU_SRC1, 1) ALU_SRC2_ZEXT = ZeroExt(ALU_SRC2, 1) ALU_CY_9B_SEXT = SignExt(ALU_CY_IN, 8) ALU_CY_9B_ZEXT = ZeroExt(ALU_CY_IN, 8) ALU_CY_9B = Choice('ALU_CY_9B', ctx.op0, [ALU_CY_9B_ZEXT, ALU_CY_9B_SEXT]) ALU_ZEXT_9B_SUM = Add(ALU_SRC1_ZEXT, Add(ALU_SRC2_ZEXT, ALU_CY_9B)) ALU_CY_ADD = Extract(8, 8, ALU_ZEXT_9B_SUM) ALU_CY_SUB = If(ULT(ALU_SRC1_ZEXT, Add(ALU_SRC2_ZEXT, ALU_CY_9B)), BitVecVal(1, 1), BitVecVal(0, 1)) ALU_CY = Choice('ALU_CY', ctx.op0, [ALU_CY_ADD, ALU_CY_SUB]) ALU_OV_9B_SRC1 = Choice('ALU_OV_9B_SRC1', ctx.op0, [ALU_SRC1_SEXT, ALU_SRC1_ZEXT]) ALU_OV_9B_SRC2 = Choice('ALU_OV_9B_SRC2', ctx.op0, [ALU_SRC2_SEXT, ALU_SRC2_ZEXT]) ALU_9B_ADD = Add(ALU_OV_9B_SRC1, Add(ALU_OV_9B_SRC2, ALU_CY_9B)) ALU_9B_SUB = Sub(ALU_OV_9B_SRC1, Add(ALU_OV_9B_SRC2, ALU_CY_9B)) ALU_9B_RES = Choice('ALU_9B_RES', ctx.op0, [ALU_9B_ADD, ALU_9B_SUB]) ALU_OV = If( Not(Equal(Extract(8, 8, ALU_9B_RES), Extract(7, 7, ALU_9B_RES))), BitVecVal(1, 1), BitVecVal(0, 1)) ACC_CY = Choice( 'ACC_CY', ctx.op0, [ctx.CY(), Extract(0, 0, ctx.ACC), Extract(7, 7, ctx.ACC), ALU_CY]) ACC_AC = Choice('ACC_AC', ctx.op0, [ctx.AC(), ALU_AC]) ACC_OV = Choice('ACC_OV', ctx.op0, [ctx.OV(), ALU_OV]) ctxACC.PSW = Concat(ACC_CY, ACC_AC, Extract(5, 3, ctx.PSW), ACC_OV, Extract(1, 0, ctx.PSW)) # multiply and divide. ctxDIV = ctxNOP.clone() ctxDIV.ACC = If(Equal(ctx.B, BitVecVal(0, 8)), BitVecVal(0xFF, 8), BVDiv(ctx.ACC, ctx.B)) ctxDIV.B = If(Equal(ctx.B, BitVecVal(0, 8)), ctx.ACC, BVRem(ctx.ACC, ctx.B)) DIV_OV = If(Equal(ctx.B, BitVecVal(0, 8)), BitVecVal(1, 1), BitVecVal(0, 1)) ctxDIV.PSW = Concat(BitVecVal(0, 1), Extract(6, 3, ctx.PSW), DIV_OV, Extract(1, 0, ctx.PSW)) ctxMUL = ctxNOP.clone() MUL_RESULT = BVMul(ZeroExt(ctx.ACC, 8), ZeroExt(ctx.B, 8)) ctxMUL.ACC = Extract(7, 0, MUL_RESULT) ctxMUL.B = Extract(15, 8, MUL_RESULT) MUL_OV = If(Not(Equal(ctxMUL.B, BitVecVal(0, 8))), BitVecVal(1, 1), BitVecVal(0, 1)) ctxMUL.PSW = Concat(BitVecVal(0, 1), Extract(6, 3, ctx.PSW), MUL_OV, Extract(1, 0, ctx.PSW)) # call type instructions push the PC onto the stack. ctxCALL = ctxNOP.clone() PC_topush = Choice('PC_topush', ctx.op0, [ctx.PC, PC_plus1, PC_plus2, PC_plus3]) PC_topush_lo = Extract(7, 0, PC_topush) PC_topush_hi = Extract(15, 8, PC_topush) PC_topush_0 = Choice('PC_topush_endianess', ctx.op0, [PC_topush_lo, PC_topush_hi]) PC_topush_1 = Choice('PC_topush_endianess', ctx.op0, [PC_topush_hi, PC_topush_lo]) PC_push_addr = Choice('PC_push_addr', ctx.op0, [ctx.SP, Add(ctx.SP, BitVecVal(1, 8))]) ctxCALL.IRAM = WriteMem(WriteMem(ctx.IRAM, PC_push_addr, PC_topush_0), Add(PC_push_addr, BitVecVal(1, 8)), PC_topush_1) # instructions where the result is a direct iram address DIR_SRC1_ADDR = Choice('DIR_SRC1_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) DIR_SRC1 = ctx.readDirect(DIR_SRC1_ADDR) DIR_SRC2_IRAM_ADDR = Choice('DIR_SRC2_IRAM_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) DIR_SRC2_IRAM = ctx.readDirect(DIR_SRC2_IRAM_ADDR) DIR_SRC2_INDIR_ADDR = Choice('DIR_SRC2_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) DIR_SRC2_INDIR = ReadMem(ctx.IRAM, DIR_SRC2_INDIR_ADDR) DIR_SRC2 = Choice( 'DIR_SRC2', ctx.op0, [ctx.op1, ctx.op2, ctx.ACC, DIR_SRC2_IRAM, DIR_SRC2_INDIR]) DIR_INC = Add(DIR_SRC1, BitVecVal(1, 8)) DIR_DEC = Sub(DIR_SRC1, BitVecVal(1, 8)) DIR_ORL = BVOr(DIR_SRC1, DIR_SRC2) DIR_ANL = BVAnd(DIR_SRC1, DIR_SRC2) DIR_XRL = BVXor(DIR_SRC1, DIR_SRC2) DIR_MOV = DIR_SRC2 DIR_RESULT = Choice('DIR_RESULT', ctx.op0, [DIR_INC, DIR_DEC, DIR_ORL, DIR_ANL, DIR_XRL, DIR_MOV]) ctxDIR = ctxNOP.writeDirect(DIR_SRC1_ADDR, DIR_RESULT) # instructions where the result is an indirect iram address SRC1_INDIR_ADDR = Choice('SRC1_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) SRC1_INDIR = ReadMem(ctx.IRAM, SRC1_INDIR_ADDR) SRC2_INDIR_DIR_ADDR = Choice('SRC2_INDIR_DIR_ADDR', ctx.op0, [ctx.op1, ctx.op2]) SRC2_INDIR_DIR = ctx.readDirect(SRC2_INDIR_DIR_ADDR) SRC2_INDIR = Choice('SRC2_INDIR', ctx.op0, [ctx.op1, ctx.op2, ctx.ACC, SRC2_INDIR_DIR]) SRC1_INDIR_INC = Add(SRC1_INDIR, BitVecVal(1, 8)) SRC1_INDIR_DEC = Sub(SRC1_INDIR, BitVecVal(1, 8)) SRC1_INDIR_MOV = SRC2_INDIR SRC1_INDIR_RESULT = Choice( 'SRC1_INDIR_RESULT', ctx.op0, [SRC1_INDIR_INC, SRC1_INDIR_DEC, SRC1_INDIR_MOV]) ctxINDIR = ctxNOP.clone() ctxINDIR.IRAM = WriteMem(ctx.IRAM, SRC1_INDIR_ADDR, SRC1_INDIR_RESULT) # push/pop instructions STK_SP = Choice( 'STK_SP', ctx.op0, [Add(ctx.SP, BitVecVal(1, 8)), Sub(ctx.SP, BitVecVal(1, 8))]) STK_IRAM_ADDR = Choice( 'STK_IRAM_ADDR', ctx.op0, [ctx.SP, Add(ctx.SP, BitVecVal(1, 8)), Sub(ctx.SP, BitVecVal(1, 8))]) STK_SRC_DIR_ADDR = Choice('STK_SRC_DIR_ADDR', ctx.op0, [ctx.op1, ctx.op2]) STK_SRC_DIR = ctx.readDirect(STK_SRC_DIR_ADDR) STK_SRC = Choice('STK_SRC', ctx.op0, [STK_SRC_DIR, ctx.ACC]) ctxPUSH = ctxNOP.clone() ctxPUSH.SP = STK_SP ctxPUSH.IRAM = WriteMem(ctx.IRAM, STK_IRAM_ADDR, STK_SRC) STK_DATA = Choice('STK_DATA', ctx.op0, [mem_SP, mem_SP_plus1, mem_SP_minus1]) ctxPOP = ctxNOP.writeDirect(STK_SRC_DIR_ADDR, STK_DATA) ctxPOP.SP = If(Equal(STK_SRC_DIR_ADDR, BitVecVal(0x81, 8)), ctxPOP.SP, STK_SP) # instructions which write to specific bit addressable registers. ctxBIT = ctxNOP.clone() BIT_SRC1_ADDR = Choice('BIT_SRC1_ADDR', ctx.op0, [ctx.op1, ctx.op2]) BIT_SRC1 = ctx.readBit(BIT_SRC1_ADDR) # some instructions write their result to the carry flag; which is also the first operand. CY_ORL = BVOr(ctx.CY(), BIT_SRC1) CY_ORLC = BVOr(ctx.CY(), Complement(BIT_SRC1)) CY_ANL = BVAnd(ctx.CY(), BIT_SRC1) CY_ANLC = BVAnd(ctx.CY(), Complement(BIT_SRC1)) CY_MOV = BIT_SRC1 CY_CPL_BIT = Complement(BIT_SRC1) CY_CPL_C = Complement(ctx.CY()) BIT_CNST1 = BitVecVal(1, 1) BIT_CNST0 = BitVecVal(0, 1) BIT_CY = Choice('BIT_CY', ctx.op0, [ CY_ORL, CY_ANL, CY_ORLC, CY_ANLC, CY_CPL_C, CY_MOV, CY_CPL_BIT, BIT_CNST1, BIT_CNST0 ]) ctxBIT.PSW = Concat(BIT_CY, Extract(6, 0, ctx.PSW)) WRBIT_CY = ctx.CY() WRBIT_CPL = Complement(BIT_SRC1) WRBIT_DATA = Choice('WRBIT_DATA', ctx.op0, [WRBIT_CY, WRBIT_CPL, BIT_CNST0, BIT_CNST1]) ctxWRBIT = ctxNOP.writeBit(BIT_SRC1_ADDR, WRBIT_DATA) # DPTR ctxDPTR = ctxNOP.clone() MOV_DPTR = Choice('MOV_DPTR', ctx.op0, [Concat(ctx.op1, ctx.op2), Concat(ctx.op2, ctx.op1)]) INC_DPTR = Add(DPTR, BitVecVal(1, 16)) ctxDPTR.DPTR = Choice('NEXT_DPTR', ctx.op0, [MOV_DPTR, INC_DPTR]) ctxDPTR.DPL = Extract(7, 0, ctxDPTR.DPTR) ctxDPTR.DPH = Extract(15, 8, ctxDPTR.DPTR) # exchange instructions. # first we deal with the direct addressed exchanges. XCHG_SRC2_DIR_ADDR = Choice('XCHG_SRC2_DIR_ADDR', ctx.op0, [ctx.op1, ctx.op2] + ctx.RxAddrs()) XCHG_SRC2_DIR = ctx.readDirect(XCHG_SRC2_DIR_ADDR) ctxXCHG_DIR = ctx.writeDirect(XCHG_SRC2_DIR_ADDR, ctx.ACC) ctxXCHG_DIR.ACC = XCHG_SRC2_DIR # and now with the indirect addressed exchanges. # note we can have both a 'full' write and a 'half' write which only # modifes the lower nibble XCHG_SRC2_INDIR_ADDR = Choice('XCHG_SRC2_INDIR_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)]) XCHG_SRC2_FULL_INDIR = ReadMem(ctx.IRAM, XCHG_SRC2_INDIR_ADDR) XCHG_SRC2_HALF_INDIR = Concat(Extract(7, 4, ctx.ACC), Extract(3, 0, XCHG_SRC2_FULL_INDIR)) XCHG_SRC2_INDIR = Choice('XCHG_SRC2_INDIR', ctx.op0, [XCHG_SRC2_FULL_INDIR, XCHG_SRC2_HALF_INDIR]) XCHG_SRC1_HALF_INDIR = Concat(Extract(7, 4, XCHG_SRC2_FULL_INDIR), Extract(3, 0, ctx.ACC)) XCHG_SRC1_INDIR = Choice('XCHG_SRC1', ctx.op0, [XCHG_SRC1_HALF_INDIR, ctx.ACC]) ctxXCHG_INDIR = ctxNOP.clone() ctxXCHG_INDIR.IRAM = WriteMem(ctx.IRAM, XCHG_SRC2_INDIR_ADDR, XCHG_SRC1_INDIR) ctxXCHG_INDIR.ACC = XCHG_SRC2_INDIR # XRAM reads and writes XRAM_ADDR_Rx = Concat( BitVecVal(0, 8), Choice('LSB_XRAM_ADDR', ctx.op0, [ctx.Rx(0), ctx.Rx(1)])) XRAM_ADDR = Choice('XRAM_ADDR', ctx.op0, [XRAM_ADDR_Rx, DPTR]) XRAM_DATA_OUT = Choice('XRAM_DATA_OUT', ctx.op0, [BitVecVal(0, 8), ctx.ACC]) ctxWRX = ctxNOP.clone() ctxWRX.XRAM_DATA_OUT = XRAM_DATA_OUT ctxWRX.XRAM_ADDR = XRAM_ADDR ctxRDX = ctxNOP.clone() ctxRDX.XRAM_ADDR = XRAM_ADDR ctxRDX.ACC = ctx.XRAM_DATA_IN # final result. ctxFINAL = CtxChoice('CTX3', ctx.op0, [ ctxNOP, ctxACC, ctxDIR, ctxDPTR, ctxPOP, ctxINDIR, ctxCALL, ctxBIT, ctxMUL, ctxDIV, ctxWRBIT, ctxPUSH, ctxDA, ctxXCHG_DIR, ctxXCHG_INDIR, ctxWRX, ctxRDX, ctxCJNE ]) syn.addOutput('PC', ctxFINAL.PC, Synthesizer.BITVEC) syn.addOutput('ACC', ctxFINAL.ACC, Synthesizer.BITVEC) syn.addOutput('IRAM', ctxFINAL.IRAM, Synthesizer.MEM) syn.addOutput('XRAM', ctxFINAL.XRAM, Synthesizer.MEM) syn.addOutput('PSW', ctxFINAL.PSW, Synthesizer.BITVEC) syn.addOutput('SP', ctxFINAL.SP, Synthesizer.BITVEC) syn.addOutput('B', ctxFINAL.B, Synthesizer.BITVEC) syn.addOutput('DPL', ctxFINAL.DPL, Synthesizer.BITVEC) syn.addOutput('DPH', ctxFINAL.DPH, Synthesizer.BITVEC) # ports syn.addOutput('P0', ctxFINAL.P0, Synthesizer.BITVEC) syn.addOutput('P1', ctxFINAL.P1, Synthesizer.BITVEC) syn.addOutput('P2', ctxFINAL.P2, Synthesizer.BITVEC) syn.addOutput('P3', ctxFINAL.P3, Synthesizer.BITVEC) # misc SFRs. syn.addOutput('PCON', ctxFINAL.PCON, Synthesizer.BITVEC) syn.addOutput('TCON', ctxFINAL.TCON, Synthesizer.BITVEC) syn.addOutput('TMOD', ctxFINAL.TMOD, Synthesizer.BITVEC) syn.addOutput('TL0', ctxFINAL.TL0, Synthesizer.BITVEC) syn.addOutput('TH0', ctxFINAL.TH0, Synthesizer.BITVEC) syn.addOutput('TL1', ctxFINAL.TL1, Synthesizer.BITVEC) syn.addOutput('TH1', ctxFINAL.TH1, Synthesizer.BITVEC) syn.addOutput('SCON', ctxFINAL.SCON, Synthesizer.BITVEC) syn.addOutput('SBUF', ctxFINAL.SBUF, Synthesizer.BITVEC) syn.addOutput('IE', ctxFINAL.IE, Synthesizer.BITVEC) syn.addOutput('IP', ctxFINAL.IP, Synthesizer.BITVEC) syn.addOutput('XRAM_ADDR', ctxFINAL.XRAM_ADDR, Synthesizer.BITVEC) syn.addOutput('XRAM_DATA_OUT', ctxFINAL.XRAM_DATA_OUT, Synthesizer.BITVEC) if logfilename: if logfilename == 'STDOUT': lf = sys.stdout else: lf = open(logfilename, 'wt') syn.debug(vb=verbosity, lf=lf, uc=unsat_core) else: lf = None cnst = Equal(ctx.op0, BitVecVal(opc, 8)) # log if lf: print >> lf, 'opcode: %02x' % opc # synthesize r = syn.synthesize(regs, [cnst], eval8051) if len(outputfilename): with open(outputfilename, 'wb') as f: pk = Pickler(f, -1) pk.dump(opc) for name, ast in itertools.izip(regs, r): pk.dump(name) pk.dump(ast) else: # print fmt = '%02x\n' + ('\n'.join(['%s'] * len(r))) + '\n' print fmt % tuple([opc] + r) # log again if lf: print >> lf, fmt % tuple([opc] + r) if lf: lf.close()
if op == 0: outputs['r'] = ((a + b) & 0xFF) if c == 227 else 0 else: outputs['r'] = (a + op) & 0xFF syn = Synthesizer() a = syn.addInput(ast.BitVecVar('a', 8)) b = syn.addInput(ast.BitVecVar('b', 8)) c = syn.addInput(ast.BitVecVar('c', 8)) r_add = ast.If( ast.Equal(c, ast.BVInRange('c', ast.BitVecVal(220, 8), ast.BitVecVal(230, 8))), ast.Add(a, b), ast.BitVecVal(0, 8)) r_inc = ast.Add( a, ast.BVInRange('inc', ast.BitVecVal(1, 8), ast.BitVecVal(11, 8))) r = ast.Choice('r', None, [r_add, r_inc]) syn.addOutput('r', r, Synthesizer.BITVEC) syn.VERBOSITY = 2 syn.logfile = sys.stdout [rsyn] = syn.synthesize(['r'], [ast.BoolVal(1)], lambda inp, out: eval(0, inp, out)) print rsyn