コード例 #1
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def emit_flags_subimm(st, reg, imm):
   st.dest = [SSADef(ctx, 'C')]
   st.op = ASGN
   st.expr = Expr(COMPARE_GE, [SSADef.cur(ctx, reg), imm])
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(COMPARE_LT, [SSADef.cur(ctx, reg), imm]))
   st.chain(ctx, st1)
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(COMPARE_EQ, [SSADef.cur(ctx, reg), imm]))
   st1.chain(ctx, st2)
   return st2
コード例 #2
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_or(st, reg, op):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
   st.chain(ctx, st1)
   st = st1
   st.expr = Expr(ORFLAGS_N, [reg, op])
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
   st.chain(ctx, st2)
   st = st2
   st.expr = Expr(ORFLAGS_Z, [reg, op])
   return st
コード例 #3
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_bit(st, mem):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
   st.chain(ctx, st1)
   st = st1
   st.expr = Expr(BITFLAGS_N, [SSADef.cur(ctx, 'M', mem)])
   st2 = SSAStatement(SSADef(ctx, 'V'), ASGN)
   st.chain(ctx, st2)
   st = st2
   st.expr = Expr(BITFLAGS_V, [SSADef.cur(ctx, 'M', mem)])
   return st
コード例 #4
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_incdec(st, reg):
   st1 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
   st.chain(ctx, st1)
   st = st1
   st.expr = Expr(NOT, [reg])
   st2 = SSAStatement(SSADef(ctx, 'N'), ASGN)
   st.chain(ctx, st2)
   st = st2
   st.expr = Expr(COMPARE_GE, [reg, 0x80])
   return st
コード例 #5
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_ld(st, reg):
   op = SSADef.cur(ctx, 'A')
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
   st.chain(ctx, st1)
   st = st1
   st.expr = Expr(COMPARE_GE, [Expr(VAR, [op]), 0x80])
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
   st.chain(ctx, st2)
   st = st2
   st.expr = Expr(NOT, [op])
   return st
コード例 #6
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_ror(st, reg1, res):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SHFLAGS_N, [res]))
   st.chain(ctx, st1)
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(NOT, [res]))
   st1.chain(ctx, st2)
   st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(AND, [reg1, 1]))
   st2.chain(ctx, st3)
   return st3
コード例 #7
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_ldimm(st, imm):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
   st.chain(ctx, st1)
   st = st1
   if imm > 0x80:
     st.expr = Expr(CONST, [1])
   else:
     st.expr = Expr(CONST, [0])
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
   st.chain(ctx, st2)
   st = st2
   if imm:
     st.expr = Expr(CONST, [0])
   else:
     st.expr = Expr(CONST, [1])
   return st
コード例 #8
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_shr(st, reg, res):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
   st.chain(ctx, st1)
   st1.expr = Expr(SHFLAGS_N, [res])
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
   st1.chain(ctx, st2)
   st2.expr = Expr(NOT, [res])
   st3 = SSAStatement(SSADef(ctx, 'C'), ASGN)
   st2.chain(ctx, st3)
   st3.expr = Expr(AND, [reg, 1])
   return st3
コード例 #9
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
def translate(self, ctx, insn, sp, end_bp, bp):
  debug(SSA, 2, 'translating', insn, hex(insn.bytes[0]))

  def chain_flags_ldimm(st, imm):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st1)
    st = st1
    if imm > 0x80:
      st.expr = Expr(CONST, [1])
    else:
      st.expr = Expr(CONST, [0])
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
    st.chain(ctx, st2)
    st = st2
    if imm:
      st.expr = Expr(CONST, [0])
    else:
      st.expr = Expr(CONST, [1])
    return st

  def chain_flags_ld(st, reg):
    op = SSADef.cur(ctx, 'A')
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st1)
    st = st1
    st.expr = Expr(COMPARE_GE, [Expr(VAR, [op]), 0x80])
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
    st.chain(ctx, st2)
    st = st2
    st.expr = Expr(NOT, [op])
    return st

  def chain_flags_incdec(st, reg):
    st1 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
    st.chain(ctx, st1)
    st = st1
    st.expr = Expr(NOT, [reg])
    st2 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st2)
    st = st2
    st.expr = Expr(COMPARE_GE, [reg, 0x80])
    return st

  def chain_flags_bit(st, mem):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st1)
    st = st1
    st.expr = Expr(BITFLAGS_N, [SSADef.cur(ctx, 'M', mem)])
    st2 = SSAStatement(SSADef(ctx, 'V'), ASGN)
    st.chain(ctx, st2)
    st = st2
    st.expr = Expr(BITFLAGS_V, [SSADef.cur(ctx, 'M', mem)])
    return st

  def chain_flags_or(st, reg, op):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st1)
    st = st1
    st.expr = Expr(ORFLAGS_N, [reg, op])
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
    st.chain(ctx, st2)
    st = st2
    st.expr = Expr(ORFLAGS_Z, [reg, op])
    return st

  def chain_flags_shl(st, reg, res):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st1)
    st1.expr = Expr(SHFLAGS_N, [res])
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
    st1.chain(ctx, st2)
    st2.expr = Expr(NOT, [res])
    st3 = SSAStatement(SSADef(ctx, 'C'), ASGN)
    st2.chain(ctx, st3)
    st3.expr = Expr(SHLFLAGS_C, [reg])
    return st3

  def chain_flags_shr(st, reg, res):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN)
    st.chain(ctx, st1)
    st1.expr = Expr(SHFLAGS_N, [res])
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN)
    st1.chain(ctx, st2)
    st2.expr = Expr(NOT, [res])
    st3 = SSAStatement(SSADef(ctx, 'C'), ASGN)
    st2.chain(ctx, st3)
    st3.expr = Expr(AND, [reg, 1])
    return st3

  def chain_flags_and(st, reg, op):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(ANDFLAGS_N, [reg, op]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(ANDFLAGS_Z, [reg, op]))
    st1.chain(ctx, st2)
    return st2

  def chain_flags_eor(st, reg, op):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(EORFLAGS_N, [reg, op]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(EORFLAGS_Z, [reg, op]))
    st1.chain(ctx, st2)
    return st2

  def chain_flags_adc(st, reg1, reg2, reg3):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(ADCFLAGS_N, [reg1, reg2, reg3]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(ADCFLAGS_Z, [reg1, reg2, reg3]))
    st1.chain(ctx, st2)
    st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(ADCFLAGS_C, [reg1, reg2, reg3]))
    st2.chain(ctx, st3)
    st4 = SSAStatement(SSADef(ctx, 'V'), ASGN, Expr(ADCFLAGS_V, [reg1, reg2, reg3]))
    st3.chain(ctx, st4)
    return st4

  def chain_flags_sbb(st, reg1, reg2, reg3):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SBBFLAGS_N, [reg1, reg2, reg3]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(SBBFLAGS_Z, [reg1, reg2, reg3]))
    st1.chain(ctx, st2)
    st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(SBBFLAGS_C, [reg1, reg2, reg3]))
    st2.chain(ctx, st3)
    st4 = SSAStatement(SSADef(ctx, 'V'), ASGN, Expr(SBBFLAGS_V, [reg1, reg2, reg3]))
    st3.chain(ctx, st4)
    return st4

  def chain_flags_rol(st, reg1, res):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SHFLAGS_N, [res]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(NOT, [res]))
    st1.chain(ctx, st2)
    st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(SHR, [reg1, 7]))
    st2.chain(ctx, st3)
    return st3

  def chain_flags_ror(st, reg1, res):
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SHFLAGS_N, [res]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(NOT, [res]))
    st1.chain(ctx, st2)
    st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(AND, [reg1, 1]))
    st2.chain(ctx, st3)
    return st3

  def emit_flags_subimm(st, reg, imm):
    st.dest = [SSADef(ctx, 'C')]
    st.op = ASGN
    st.expr = Expr(COMPARE_GE, [SSADef.cur(ctx, reg), imm])
    st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(COMPARE_LT, [SSADef.cur(ctx, reg), imm]))
    st.chain(ctx, st1)
    st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(COMPARE_EQ, [SSADef.cur(ctx, reg), imm]))
    st1.chain(ctx, st2)
    return st2

  # normally, add() will follow the flow of the machine code instructions;
  # if we know better (such as with branches with constant conditions), we
  # can put a list of successor instructions here
  next = None

  st = SSAStatement()

  debug(SSA, 2, 'translating', insn, hex(insn.bytes[0]), 'to', st.num)

  opc = insn.bytes[0]

  if insn == None:
    return None
  
  st_start = st
  self.ssa_for_insn[insn] = st
  st.insn = insn

  if len(insn.comefrom) > 1:
    debug(SSA, 3, 'phiing')
    for g in ctx.local_indices.values():
      st.dest = [SSADef(ctx, g.type, g.addr)]
      st.op = ASGN
      st.expr = Expr(PHI, [g])
      for h in insn.comefrom:
        if h in self.last_ssa_for_insn:
          #print('reaching from', self.last_ssa_for_insn[h], [str(x) + '(' + repr(x) + ')' for x in self.last_ssa_for_insn[h].reaching])
          for i in self.last_ssa_for_insn[h].reaching:
            if i.type == g.type and i.addr == g.addr and not i in st.expr.ops:
              st.expr.ops += [i]
      st1 = SSAStatement()
      st.chain(ctx, st1)
      st = st1
  
  def abs():
    return insn.bytes[1] + (insn.bytes[2] << 8)
  def zp():
    return insn.bytes[1]
  def imm():
    return insn.bytes[1]

  def do_st_abs(reg):
    if self.is_io(abs()):
      st.op = IMPURE
      st.dest = []
      st.expr = Expr(IOOUT, [abs(), SSADef.cur(ctx, reg)])
      st.expr.dont_propagate = True
      st.expr.dont_eliminate = True
    else:
      st.dest = [SSADef(ctx, 'M', abs())]
      st.op = ASGN
      st.expr = Expr(VAR, [SSADef.cur(ctx, reg)])

  def do_ld_abs(reg):
    nonlocal st
    st.dest = [SSADef(ctx, reg)]
    st.op = ASGN
    if self.is_io(abs()):
      st.expr = Expr(IOIN, [abs()])
      st.expr.dont_propagate = True
      st.expr.dont_eliminate = True
    else:
      st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', abs())])
    st = chain_flags_ld(st, reg)

  def do_st_xy(src, addr, reg):
    st.dest = []
    st.op = IMPURE
    if self.is_io(addr):
      st.expr = Expr(IOOUT, [Expr(ADD, [addr, SSADef.cur(ctx, reg)]), SSADef.cur(ctx, src)])
      st.expr.dont_propagate = True
      st.expr.dont_eliminate = True
    else:
      st.expr = Expr(STORE, [SSADef.cur(ctx, src), addr, SSADef.cur(ctx, reg)])

  def do_ld_xy(dst, addr, reg):
    nonlocal st
    st.dest = [SSADef(ctx, dst)]
    st.op = ASGN
    if self.is_io(addr):
      st.expr = Expr(IOIN, [Expr(ADD, [addr, SSADef.cur(ctx, reg)])])
      st.expr.dont_propagate = True
      st.expr.dont_eliminate = True
    else:
      st.expr = Expr(LOAD, [addr, SSADef.cur(ctx, reg)])
    st = chain_flags_ld(st, dst)

  def do_branch(flag, positive):
    nonlocal next, st
    if insn.fake_branch >= 0:
      next = [insn.next[insn.fake_branch]]
      st.op = ASGN
      st.expr = Expr(NOP, [0])
    else:
      st.op = BRANCH_COND
      st.expr = Expr(VAR if positive else NOT, [SSADef.cur(ctx, flag)])
    st.dest = []
  
  if opc == 0x00:	# BRK
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['brk', imm()])
  elif opc == 0x01:	# ORA (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_mem = Expr(LOAD, [addr, 0])
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(OR, [current_a, current_mem])
    st = chain_flags_or(st, current_a, current_mem)
  elif opc == 0x05:	# ORA zp
    current_a = SSADef.cur(ctx, 'A')
    st.op = ASGN
    st.expr = Expr(OR, [current_a, SSADef.cur(ctx, 'M', zp())])
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_or(st, current_a, SSADef.cur(ctx, 'M', zp()))
  elif opc == 0x06:	# ASL zp
    current_mem = SSADef.cur(ctx, 'M', zp())
    st.op = ASGN
    st.expr = Expr(SHL, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', zp())]
    st = chain_flags_shl(st, current_mem, st.expr)
  elif opc == 0x08:	# PHP
    st.dest = [SSADef(ctx, 's', sp)]
    sp -= 1
    st.op = ASGN
    st.expr = Expr(FLAGS, [SSADef.cur(ctx, 'C'),SSADef.cur(ctx, 'Z'),SSADef.cur(ctx, 'N'),SSADef.cur(ctx, 'V')])
  elif opc == 0x09:	# ORA imm
    current_a = SSADef.cur(ctx, 'A')
    st.op = ASGN
    st.expr = Expr(OR, [current_a, imm()])
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_or(st, current_a, imm())
  elif opc == 0x0a:	# ASL A
    current_a = SSADef.cur(ctx, 'A')
    st.op = ASGN
    st.expr = Expr(SHL, [current_a, 1])
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_shl(st, current_a, st.expr)
  elif opc == 0x0d:	# ORA abs
    current_a = SSADef.cur(ctx, 'A')
    st.op = ASGN
    st.expr = Expr(OR, [current_a, SSADef.cur(ctx, 'M', abs())])
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_or(st, current_a, SSADef.cur(ctx, 'M', abs()))
  elif opc == 0x0e:	# ASL abs
    current_mem = SSADef.cur(ctx, 'M', abs())
    st.op = ASGN
    st.expr = Expr(SHL, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', abs())]
    st = chain_flags_shl(st, current_mem, st.expr)
  elif opc == 0x10:	# BPL dd
    do_branch('N', False)
  elif opc == 0x11:	# ORA (zp),Y
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')])
    st.expr = Expr(OR, [current_a, operand])
    st = chain_flags_or(st, current_a, operand)
  elif opc == 0x15:	# ORA zp,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    st.expr = Expr(OR, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_or(st, current_a, current_mem)
  elif opc == 0x16:	# ASL zp,X
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    shlex = Expr(SHL, [current_mem, 1])
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [shlex, zp(), SSADef.cur(ctx, 'X')])
    st = chain_flags_shl(st, current_mem, shlex)
  elif opc == 0x18:	# CLC
    st.dest = [SSADef(ctx, 'C')]
    st.expr = Expr(CONST, [0])
    st.op = ASGN
  elif opc == 0x19:	# ORA abs,Y
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')])
    st.expr = Expr(OR, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_or(st, current_a, current_mem)
  elif opc == 0x1d:	# ORA abs,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    st.expr = Expr(OR, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_or(st, current_a, current_mem)
  elif opc == 0x1e:	# ASL abs,X
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    shlex = Expr(SHL, [current_mem, 1])
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [shlex, abs(), SSADef.cur(ctx, 'X')])
    st = chain_flags_shl(st, current_mem, shlex)
  elif opc == 0x20:	# JSR abs
    st.expr = Expr(ARGS, [abs()] + self.fun_args(ctx, insn.next[1], st, sp))
    st.dest = self.fun_returns(ctx, insn.next[1], st)
    st.op = CALL
  elif opc == 0x21:	# AND (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_mem = Expr(LOAD, [addr, 0])
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(AND, [current_a, current_mem])
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x24:	# BIT zp
    st.expr = Expr(COMPARE_EQ, [Expr(AND, [SSADef.cur(ctx, 'A'), SSADef.cur(ctx, 'M', zp())]), 0])
    st.dest = [SSADef(ctx, 'Z')]
    st.op = ASGN
    st = chain_flags_bit(st, zp())
  elif opc == 0x25:	# AND zp
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', zp())
    st.expr = Expr(AND, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x26:	# ROL zp
    current_mem = SSADef.cur(ctx, 'M', zp())
    current_c = SSADef.cur(ctx, 'C')
    st.op = ASGN
    st.expr = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c])
    st.expr.dont_propagate = True
    st.dest = [SSADef(ctx, 'M', zp())]
    st = chain_flags_rol(st, current_mem, st.expr)
  elif opc == 0x28:	# PLP
    sp += 1
    flags = SSADef.cur(ctx, 's', sp)
    for i in [('C', DEFLAGS_C), ('Z', DEFLAGS_Z), ('N', DEFLAGS_N), ('V', DEFLAGS_V)]:
      st.op = ASGN
      st.dest = [SSADef(ctx, i[0])]
      st.expr = Expr(i[1], [flags])
      if i[0] != 'V':
        st1 = SSAStatement()
        st.chain(ctx, st1)
        st = st1
  elif opc == 0x29:	# AND imm
    current_a = SSADef.cur(ctx, 'A')
    st.op = ASGN
    st.expr = Expr(AND, [current_a, imm()])
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_and(st, current_a, imm())
  elif opc == 0x2a:	# ROL A
    current_a = SSADef.cur(ctx, 'A')
    current_c = SSADef.cur(ctx, 'C')
    st.op = ASGN
    st.expr = Expr(OR, [Expr(SHL, [current_a, 1]), current_c])
    st.expr.dont_propagate = True
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_rol(st, current_a, st.expr)
  elif opc == 0x2c:	# BIT abs
    st.expr = Expr(COMPARE_EQ, [Expr(AND, [SSADef.cur(ctx, 'A'), SSADef.cur(ctx, 'M', abs())]), 0])
    st.dest = [SSADef(ctx, 'Z')]
    st.op = ASGN
    st = chain_flags_bit(st, abs())
  elif opc == 0x2d:	# AND abs
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', abs())
    st.expr = Expr(AND, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x2e:	# ROL abs
    current_mem = SSADef.cur(ctx, 'M', abs())
    current_c = SSADef.cur(ctx, 'C')
    st.op = ASGN
    st.expr = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c])
    st.expr.dont_propagate = True
    st.dest = [SSADef(ctx, 'M', abs())]
    st = chain_flags_rol(st, current_mem, st.expr)
  elif opc == 0x30:	# BMI dd
    do_branch('N', True)
  elif opc == 0x31:	# AND (zp),Y
    current_mem = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')])
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(AND, [current_a, current_mem])
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x35:	# AND zp,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    st.expr = Expr(AND, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x36:	# ROL zp,X
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_c = SSADef.cur(ctx, 'C')
    st.op = IMPURE
    rolex = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c])
    rolex.dont_propagate = True
    st.dest = []
    st.expr = Expr(STORE, [rolex, zp(), SSADef.cur(ctx, 'X')])
    st = chain_flags_rol(st, current_mem, rolex)
  elif opc == 0x38:	# SEC
    st.dest = [SSADef(ctx, 'C')]
    st.op = ASGN
    st.expr = Expr(CONST, [1])
  elif opc == 0x39:	# AND abs,Y
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')])
    st.expr = Expr(AND, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x3d:	# AND abs,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    st.expr = Expr(AND, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_and(st, current_a, current_mem)
  elif opc == 0x3e:	# ROL abs,X
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    current_c = SSADef.cur(ctx, 'C')
    st.op = IMPURE
    rolex = Expr(OR, [Expr(SHL, [current_mem, 1]), current_c])
    rolex.dont_propagate = True
    st.dest = []
    st.expr = Expr(STORE, [rolex, abs(), SSADef.cur(ctx, 'X')])
    st = chain_flags_rol(st, current_mem, rolex)
  elif opc == 0x40:	# RTI
    st.dest = []
    st.op = RETURN
    st.expr = None
    st.add_comment('RTI')
  elif opc == 0x41:	# EOR (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_mem = Expr(LOAD, [addr, 0])
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(EOR, [current_a, current_mem])
    st = chain_flags_eor(st, current_a, current_mem)
  elif opc == 0x45:	# EOR zp
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', zp())
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(EOR, [current_a, current_mem])
    st = chain_flags_eor(st, current_a, current_mem)
  elif opc == 0x46:	# LSR zp
    current_mem = SSADef.cur(ctx, 'M', zp())
    st.op = ASGN
    st.expr = Expr(SHR, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', zp())]
    st = chain_flags_shr(st, current_mem, st.expr)
  elif opc == 0x48:	# PHA
    st.dest = [SSADef(ctx, 's', sp)]
    sp -= 1
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')])
  elif opc == 0x49:	# EOR imm
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(EOR, [current_a, imm()])
    st = chain_flags_eor(st, current_a, imm())
  elif opc == 0x4a:	# LSR A
    current_a = SSADef.cur(ctx, 'A')
    st.op = ASGN
    st.expr = Expr(SHR, [current_a, 1])
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_shr(st, current_a, st.expr)
  elif opc == 0x4c:	# JMP
    if insn.next[0] == insn:
      st.op = ENDLESS_LOOP
      st.expr = None
      st.dest = []
    elif insn.next[0].sym != None:
      # tail call
      if insn.next[0] == ctx.graph.first_insn:
        debug(SSA, 2, 'tail recursion at', insn)
        # recursion causes us grief with args/rets, so we avoid it if
        # possible; here, we can just let the jmp run its course
        st.op = ASGN
        st.dest = []
        st.expr = Expr(NOP, [0])
      else:
        debug(SSA, 2, 'tail call at', insn)
        st.expr = Expr(ARGS, [abs()] + self.fun_args(ctx, insn.next[0], st, sp))
        st.dest = self.fun_returns(ctx, insn.next[0], st)
        st.op = CALL
        st1 = SSAStatement()
        st.chain(ctx, st1)
        st = st1
        st.dest = []
        st.op = RETURN
        st.expr = None
        next = []
    else:
      st.op = ASGN
      st.dest = []
      st.expr = Expr(NOP, [0])
  elif opc == 0x4d:	# EOR abs
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', abs())
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(EOR, [current_a, current_mem])
    st = chain_flags_eor(st, current_a, current_mem)
  elif opc == 0x4e:	# LSR abs
    current_mem = SSADef.cur(ctx, 'M', abs())
    st.op = ASGN
    st.expr = Expr(SHR, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', abs())]
    st = chain_flags_shr(st, current_mem, st.expr)
  elif opc == 0x50:	# BVC
    do_branch('V', False)
  elif opc == 0x51:	# EOR (zp),Y
    current_a = SSADef.cur(ctx, 'A')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')])
    st.expr = Expr(EOR, [current_a, operand])
    st = chain_flags_eor(st, current_a, operand)
  elif opc == 0x55:	# EOR zp,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    st.expr = Expr(EOR, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_eor(st, current_a, current_mem)
  elif opc == 0x56:	# LSR zp,X
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    shrex = Expr(SHR, [current_mem, 1])
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [shrex, zp(), SSADef.cur(ctx, 'X')])
    st = chain_flags_shr(st, current_mem, shrex)
  elif opc == 0x58:	# CLI
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['cli'])
  elif opc == 0x59:	# EOR abs,Y
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')])
    st.expr = Expr(EOR, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_eor(st, current_a, current_mem)
  elif opc == 0x5d:	# EOR abs,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    st.expr = Expr(EOR, [current_a, current_mem])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st = chain_flags_eor(st, current_a, current_mem)
  elif opc == 0x5e:	# LSR abs,X
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    shrex = Expr(SHR, [current_mem, 1])
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [shrex, abs(), SSADef.cur(ctx, 'X')])
    st = chain_flags_shr(st, current_mem, shrex)
  elif opc == 0x60:	# RTS
    st.dest = []
    st.op = RETURN
    st.expr = None
  elif opc == 0x61:	# ADC (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [addr, 0])
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, current_mem, current_c])
    st = chain_flags_adc(st, current_a, current_mem, current_c)
  elif opc == 0x65:	# ADC zp
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', zp())
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, current_mem, current_c])
    st = chain_flags_adc(st, current_a, current_mem, current_c)
  elif opc == 0x66:	# ROR zp
    current_mem = SSADef.cur(ctx, 'M', zp())
    current_c = SSADef.cur(ctx, 'C')
    st.op = ASGN
    st.expr = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])])
    st.expr.dont_propagate = True
    st.dest = [SSADef(ctx, 'M', zp())]
    st = chain_flags_ror(st, current_mem, st.expr)
  elif opc == 0x68:	# PLA
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    sp += 1
    st.expr = Expr(VAR, [SSADef.cur(ctx, 's', sp)])
    st = chain_flags_ld(st, 'A')
  elif opc == 0x69:	# ADC imm
    current_a = SSADef.cur(ctx, 'A')
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, imm(), current_c])
    st = chain_flags_adc(st, current_a, imm(), current_c)
  elif opc == 0x6a:	# ROR A
    current_a = SSADef.cur(ctx, 'A')
    current_c = SSADef.cur(ctx, 'C')
    st.op = ASGN
    st.expr = Expr(OR, [Expr(SHR, [current_a, 1]), Expr(SHL, [current_c, 7])])
    st.expr.dont_propagate = True
    st.dest = [SSADef(ctx, 'A')]
    st = chain_flags_ror(st, current_a, st.expr)
  elif opc == 0x6c:	# JMP ind
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['jmp', SSADef.cur(ctx, 'M', abs())])
    st.add_comment('XXX: indirect jump not implemented yet')
  elif opc == 0x6d:	# ADC abs
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', abs())
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, current_mem, current_c])
    st = chain_flags_adc(st, current_a, current_mem, current_c)
  elif opc == 0x6e:	# ROR abs
    current_mem = SSADef.cur(ctx, 'M', abs())
    current_c = SSADef.cur(ctx, 'C')
    st.op = ASGN
    st.expr = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])])
    st.expr.dont_propagate = True
    st.dest = [SSADef(ctx, 'M', abs())]
    st = chain_flags_ror(st, current_mem, st.expr)
  elif opc == 0x70:	# BVS dd
    do_branch('V', True)
  elif opc == 0x71:	# ADC (zp),Y
    current_a = SSADef.cur(ctx, 'A')
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')])
    st.expr = Expr(ADD, [current_a, operand, current_c])
    st = chain_flags_adc(st, current_a, operand, current_c)
  elif opc == 0x75:	# ADC zp,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, current_mem, current_c])
    st = chain_flags_adc(st, current_a, current_mem, current_c)
  elif opc == 0x76:	# ROR zp,X
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_c = SSADef.cur(ctx, 'C')
    st.op = IMPURE
    rorex = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])])
    rorex.dont_propagate = True
    st.dest = []
    st.expr = Expr(STORE, [rorex, zp(), SSADef.cur(ctx, 'X')])
    st = chain_flags_ror(st, current_mem, rorex)
  elif opc == 0x78: 	# SEI
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['sei'])
  elif opc == 0x79:	# ADC abs,Y
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')])
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, current_mem, current_c])
    st = chain_flags_adc(st, current_a, current_mem, current_c)
  elif opc == 0x7d:	# ADC abs,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    current_c = SSADef.cur(ctx, 'C')
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(ADD, [current_a, current_mem, current_c])
    st = chain_flags_adc(st, current_a, current_mem, current_c)
  elif opc == 0x7e:	# ROR abs,X
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    current_c = SSADef.cur(ctx, 'C')
    st.op = IMPURE
    rorex = Expr(OR, [Expr(SHR, [current_mem, 1]), Expr(SHL, [current_c, 7])])
    rorex.dont_propagate = True
    st.dest = []
    st.expr = Expr(STORE, [rorex, abs(), SSADef.cur(ctx, 'X')])
    st = chain_flags_ror(st, current_mem, rorex)
  elif opc == 0x81:	# STA (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    st.op = IMPURE
    st.dest = []
    st.expr = Expr(STORE, [SSADef.cur(ctx, 'A'), addr, 0])
  elif opc == 0x84:	# STY zp
    st.dest = [SSADef(ctx, 'M', zp())]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'Y')])
  elif opc == 0x85:	# STA zp
    st.dest = [SSADef(ctx, 'M', zp())]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')])
  elif opc == 0x86:	# STX zp
    st.dest = [SSADef(ctx, 'M', zp())]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'X')])
  elif opc == 0x88:	# DEY
    st.expr = Expr(SUB, [SSADef.cur(ctx, 'Y'), 1])
    st.dest = [SSADef(ctx, 'Y')]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'Y'))
  elif opc == 0x8a:	# TXA
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'X')])
    st = chain_flags_ld(st, 'A')
  elif opc == 0x8c:	# STY abs
    do_st_abs('Y')
  elif opc == 0x8d:	# STA abs
    do_st_abs('A')
  elif opc == 0x8e:	# STX abs
    do_st_abs('X')
  elif opc == 0x90:	# BCC dd
    do_branch('C', False)
  elif opc == 0x91:	# STA (zp),Y
    current_ind = SSADef.cur(ctx, 'M', zp())
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [SSADef.cur(ctx, 'A'), current_ind, SSADef.cur(ctx, 'Y')])
  elif opc == 0x94:	# STY zp,X
    do_st_xy('Y', zp(), 'X')
  elif opc == 0x95:	# STA zp,X
    do_st_xy('A', zp(), 'X')
  elif opc == 0x96:	# STX zp,Y
    do_st_xy('X', zp(), 'Y')
  elif opc == 0x98:	# TYA
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'Y')])
    st = chain_flags_ld(st, 'A')
  elif opc == 0x99:	# STA abs,Y
    do_st_xy('A', abs(), 'Y')
  elif opc == 0x9a:	# TXS
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['setsp', SSADef.cur(ctx, 'X')])
  elif opc == 0x9d:	# STA abs,X
    do_st_xy('A', abs(), 'X')
  elif opc == 0xa0:	# LDY imm
    st.dest = [SSADef(ctx, 'Y')]
    st.op = ASGN
    st.expr = Expr(CONST, [imm()])
    st = chain_flags_ldimm(st, imm())
  elif opc == 0xa1:	# LDA (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(VAR, [Expr(LOAD, [addr, 0])])
    st = chain_flags_ld(st, 'A')
  elif opc == 0xa2:	# LDX imm
    st.dest = [SSADef(ctx, 'X')]
    st.op = ASGN
    st.expr = Expr(CONST, [imm()])
    st = chain_flags_ldimm(st, imm())
  elif opc == 0xa4:	# LDY zp
    st.dest = [SSADef(ctx, 'Y')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', zp())])
    st = chain_flags_ld(st, 'Y')
  elif opc == 0xa5:	# LDA zp
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', zp())])
    st = chain_flags_ld(st, 'A')
  elif opc == 0xa6:	# LDX zp
    st.dest = [SSADef(ctx, 'X')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', zp())])
    st = chain_flags_ld(st, 'X')
  elif opc == 0xa8:	# TAY
    st.dest = [SSADef(ctx, 'Y')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')])
    st = chain_flags_ld(st, 'Y')
  elif opc == 0xa9:	# LDA imm
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(CONST, [imm()])
    st = chain_flags_ldimm(st, imm())
  elif opc == 0xaa:	# TAX
    st.dest = [SSADef(ctx, 'X')]
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 'A')])
    st = chain_flags_ld(st, 'X')
  elif opc == 0xac:	# LDY abs
    do_ld_abs('Y')
  elif opc == 0xad:	# LDA abs
    do_ld_abs('A')
  elif opc == 0xae:	# LDX abs
    do_ld_abs('X')
  elif opc == 0xb0:	# BCS dd
    do_branch('C', True)
  elif opc == 0xb1:	# LDA (zp),Y
    current_ind = SSADef.cur(ctx, 'M', zp())
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(LOAD, [current_ind, SSADef.cur(ctx, 'Y')])
    st = chain_flags_ld(st, 'A')
  elif opc == 0xb4:	# LDY zp,X
    do_ld_xy('Y', zp(), 'X')
  elif opc == 0xb5:	# LDA zp,X
    do_ld_xy('A', zp(), 'X')
  elif opc == 0xb6:	# LDX zp,Y
    do_ld_xy('X', zp(), 'Y')
  elif opc == 0xb8:	# CLV
    st.op = ASGN
    st.dest = [SSADef(ctx, 'V')]
    st.expr = Expr(CONST, [0])
  elif opc == 0xb9:	# LDA abs,Y
    do_ld_xy('A', abs(), 'Y')
  elif opc == 0xba:	# TSX
    st.dest = [SSADef(ctx, 'X')]
    st.op = ASGN
    st.expr = Expr(INTRINSIC, ['getsp'])
  elif opc == 0xbc:	# LDY abs,X
    do_ld_xy('Y', abs(), 'X')
  elif opc == 0xbd:	# LDA abs,X
    do_ld_xy('A', abs(), 'X')
  elif opc == 0xbe:	# LDX abs,Y
    do_ld_xy('X', abs(), 'Y')
  elif opc == 0xc0:	# CPY imm
    st = emit_flags_subimm(st, 'Y', imm())
  elif opc == 0xc1:	# CMP (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    st = emit_flags_subimm(st, 'A', Expr(LOAD, [addr, 0]))
  elif opc == 0xc4:	# CPY zp
    st = emit_flags_subimm(st, 'Y', SSADef.cur(ctx, 'M', zp()))
  elif opc == 0xc5:	# CMP zp
    st = emit_flags_subimm(st, 'A', SSADef.cur(ctx, 'M', zp()))
  elif opc == 0xc6:	# DEC zp
    current_mem = SSADef.cur(ctx, 'M', zp())
    st.expr = Expr(SUB, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', zp())]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', zp()))
  elif opc == 0xc8:	# INY
    st.expr = Expr(ADD, [SSADef.cur(ctx, 'Y'), 1])
    st.dest = [SSADef(ctx, 'Y')]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'Y'))
  elif opc == 0xc9:	# CMP imm
    st = emit_flags_subimm(st, 'A', imm())
  elif opc == 0xca:	# DEX
    current_x = SSADef.cur(ctx, 'X')
    st.expr = Expr(SUB, [current_x, 1])
    st.dest = [SSADef(ctx, 'X')]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'X'))
  elif opc == 0xcc:	# CPY abs
    st = emit_flags_subimm(st, 'Y', SSADef.cur(ctx, 'M', abs()))
  elif opc == 0xcd:	# CMP abs
    st = emit_flags_subimm(st, 'A', SSADef.cur(ctx, 'M', abs()))
  elif opc == 0xce:	# DEC abs
    current_mem = SSADef.cur(ctx, 'M', abs())
    st.expr = Expr(SUB, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', abs())]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', abs()))
  elif opc == 0xd0:	# BNE dd
    do_branch('Z', False)
  elif opc == 0xd1:	# CMP (zp),Y
    operand = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')])
    st = emit_flags_subimm(st, 'A', operand)
  elif opc == 0xd5:	# CMP zp,X
    st = emit_flags_subimm(st, 'A', Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')]))
  elif opc == 0xd6:	# DEC zp,X
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    subex = Expr(SUB, [current_mem, 1])
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [subex, zp(), SSADef.cur(ctx, 'X')])
    st = chain_flags_incdec(st, subex)
  elif opc == 0xd8:	# CLD
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['cld'])
    st.add_comment('XXX: CLD unimplemented')
  elif opc == 0xd9:	# CMP abs,Y
    st = emit_flags_subimm(st, 'A', Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')]))
  elif opc == 0xdd:	# CMP abs,X
    st = emit_flags_subimm(st, 'A', Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')]))
  elif opc == 0xde:	# DEC abs,X
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    subex = Expr(SUB, [current_mem, 1])
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(STORE, [subex, abs(), SSADef.cur(ctx, 'X')])
    st = chain_flags_incdec(st, subex)
  elif opc == 0xe0:	# CPX imm
    st = emit_flags_subimm(st, 'X', imm())
  elif opc == 0xe1:	# SBC (zp,X)
    addr = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [addr, 0])
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xe4:	# CPX zp
    st = emit_flags_subimm(st, 'X', SSADef.cur(ctx, 'M', zp()))
  elif opc == 0xe5:	# SBC zp
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', zp())
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xe6:	# INC zp
    current_mem = SSADef.cur(ctx, 'M', zp())
    st.expr = Expr(ADD, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', zp())]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', zp()))
  elif opc == 0xe8:	# INX
    current_x = SSADef.cur(ctx, 'X')
    st.expr = Expr(ADD, [current_x, 1])
    st.dest = [SSADef(ctx, 'X')]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'X'))
  elif opc == 0xe9:	# SBC imm
    current_a = SSADef.cur(ctx, 'A')
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, imm(), current_borrow])
    st = chain_flags_sbb(st, current_a, imm(), current_borrow)
  elif opc == 0xea:	# NOP
    st.op = ASGN
    st.dest = []
    st.expr = Expr(NOP, [0])
  elif opc == 0xec:	# CPX abs
    st = emit_flags_subimm(st, 'X', SSADef.cur(ctx, 'M', abs()))
  elif opc == 0xed:	# SBC abs
    current_a = SSADef.cur(ctx, 'A')
    current_mem = SSADef.cur(ctx, 'M', abs())
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xee:	# INC abs
    current_mem = SSADef.cur(ctx, 'M', abs())
    st.expr = Expr(ADD, [current_mem, 1])
    st.dest = [SSADef(ctx, 'M', abs())]
    st.op = ASGN
    st = chain_flags_incdec(st, SSADef.cur(ctx, 'M', abs()))
  elif opc == 0xf0:	# BEQ dd
    do_branch('Z', True)
  elif opc == 0xf1:	# SBC (zp),Y
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [SSADef.cur(ctx, 'M', zp()), SSADef.cur(ctx, 'Y')])
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xf5:	# SBC zp,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xf6:	# INC zp,X
    current_mem = Expr(LOAD, [zp(), SSADef.cur(ctx, 'X')])
    result = Expr(ADD, [current_mem, 1])
    st.expr = Expr(STORE, [result, zp(), SSADef.cur(ctx, 'X')])
    st.dest = []
    st.op = IMPURE
    st = chain_flags_incdec(st, result)
  elif opc == 0xf8:	# SED
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['sed'])
    st.add_comment('XXX: SED unimplemented')
  elif opc == 0xf9:	# SBC abs,Y
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'Y')])
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xfd:	# SBC abs,X
    current_a = SSADef.cur(ctx, 'A')
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    current_borrow = Expr(SUB, [1, SSADef.cur(ctx, 'C')])
    st.dest = [SSADef(ctx, 'A')]
    st.op = ASGN
    st.expr = Expr(SUB, [current_a, current_mem, current_borrow])
    st = chain_flags_sbb(st, current_a, current_mem, current_borrow)
  elif opc == 0xfe:	# INC abs,X
    current_mem = Expr(LOAD, [abs(), SSADef.cur(ctx, 'X')])
    result = Expr(ADD, [current_mem, 1])
    st.expr = Expr(STORE, [result, abs(), SSADef.cur(ctx, 'X')])
    st.dest = []
    st.op = IMPURE
    st = chain_flags_incdec(st, result)
  elif opc == OPC_OUTOFRANGE:
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['thunk', insn.addr])
  elif opc in [      0x02, 0x03, 0x04, 0x07,             0x0b, 0x0c,       0x0f,
                     0x12, 0x13, 0x14, 0x17,       0x1a, 0x1b, 0x1c,       0x1f,
                     0x22, 0x23,       0x27,             0x2b,             0x2f,
                     0x32, 0x33, 0x34, 0x37,       0x3a, 0x3b, 0x3c,       0x3f,
                     0x42, 0x43, 0x44, 0x47,             0x4b,             0x4f,
                     0x52, 0x53, 0x54, 0x57,       0x5a, 0x5b, 0x5c,       0x5f,
                     0x62, 0x63, 0x64, 0x67,             0x6b,             0x6f,
                     0x72, 0x73, 0x74, 0x77,       0x7a, 0x7b, 0x7c,       0x7f,
               0x80, 0x82, 0x83,       0x87, 0x89,       0x8b,             0x8f,
                     0x92, 0x93,       0x97,             0x9b, 0x9c, 0x9e, 0x9f,
                           0xa3,       0xa7,             0xab,             0xaf,
                     0xb2, 0xb3,       0xb7,             0xbb,             0xbf,
                     0xc2, 0xc3,       0xc7,             0xcb,             0xcf,
                     0xd2, 0xd3, 0xd4, 0xd7,       0xda, 0xdb, 0xdc,       0xdf,
                     0xe2, 0xe3,       0xe7,             0xeb,             0xef,
                     0xf2, 0xf3, 0xf4, 0xf7,       0xfa, 0xfb, 0xfc,       0xff]:
    # illegal opcode
    # XXX: add switch to allow 'useful' illegal opcodes
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['illegal', opc])
    st.dest = []
    st.add_comment('XXX: unimplemented illegal opcode')
  else:
    raise InternalError('unknown opcode ' + hex(opc))

  # all current indices are reaching, with the exception of anything
  # below the stack pointer
  st.reaching = []
  for i in ctx.local_indices.values():
    if i.type != 's':# or i.addr > sp:
      st.reaching += [i]

  self.last_ssa_for_insn[insn] = st
  return (st_start, st, sp, bp, end_bp, next)
コード例 #10
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_sbb(st, reg1, reg2, reg3):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(SBBFLAGS_N, [reg1, reg2, reg3]))
   st.chain(ctx, st1)
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(SBBFLAGS_Z, [reg1, reg2, reg3]))
   st1.chain(ctx, st2)
   st3 = SSAStatement(SSADef(ctx, 'C'), ASGN, Expr(SBBFLAGS_C, [reg1, reg2, reg3]))
   st2.chain(ctx, st3)
   st4 = SSAStatement(SSADef(ctx, 'V'), ASGN, Expr(SBBFLAGS_V, [reg1, reg2, reg3]))
   st3.chain(ctx, st4)
   return st4
コード例 #11
0
ファイル: ssa_6502.py プロジェクト: chozekun/decomp-6502-arm
 def chain_flags_eor(st, reg, op):
   st1 = SSAStatement(SSADef(ctx, 'N'), ASGN, Expr(EORFLAGS_N, [reg, op]))
   st.chain(ctx, st1)
   st2 = SSAStatement(SSADef(ctx, 'Z'), ASGN, Expr(EORFLAGS_Z, [reg, op]))
   st1.chain(ctx, st2)
   return st2
コード例 #12
0
def translate(self, ctx, insn, sp, end_bp, bp):

  # normally, add() will follow the flow of the machine code instructions;
  # if we know better (such as with branches with constant conditions), we
  # can put a list of successor instructions here
  next = None

  st = SSAStatement()

  debug(SSA, 2, 'translating', insn, hex(insn.bytes[0]), 'to', st.num)

  opc = insn.bytes[0]

  if insn == None:
    return None
  
  st_start = st
  self.ssa_for_insn[insn] = st
  st.insn = insn

  if len(insn.comefrom) > 1:
    debug(SSA, 3, 'phiing')
    for g in ctx.local_indices.values():
      st.dest = [SSADef(ctx, g.type, g.addr)]
      st.op = ASGN
      st.expr = Expr(PHI, [g])
      for h in insn.comefrom:
        if h in self.last_ssa_for_insn:
          #print('reaching from', self.last_ssa_for_insn[h], [str(x) + '(' + repr(x) + ')' for x in self.last_ssa_for_insn[h].reaching])
          for i in self.last_ssa_for_insn[h].reaching:
            if i.type == g.type and i.addr == g.addr and not i in st.expr.ops:
              st.expr.ops += [i]
      st1 = SSAStatement()
      st.chain(ctx, st1)
      st = st1
  

  def rot_imm(imm8, rs):
    return ((imm8 >> rs * 2) | (imm8 << (32 - rs * 2))) & 0xffffffff

  def do_ld_abs(reg, addr, size):
    nonlocal st
    st.op = ASGN
    if self.is_io(addr):
      if size == 1:
        op = IOIN
      elif size == 2:
        op = IOIN16
      else:
        op = IOIN32
      st.expr = Expr(op, [addr])
      st.expr.dont_propagate = True
      st.expr.dont_eliminate = True
    else:
      if size == 4:
        st.expr = Expr(VAR, [SSADef.cur(ctx, 'Mw', addr)])
      elif size == 2:
        st.expr = Expr(VAR, [SSADef.cur(ctx, 'Mh', addr)])
      elif size == 1:
        st.expr = Expr(VAR, [SSADef.cur(ctx, 'M', addr)])
      else:
        raise InternalError('unhandled size ' + str(size))
    st.dest = [SSADef(ctx, reg)]

  
  def do_ld_reg(dst, off, reg, size):
    nonlocal st
    st.op = ASGN
    # XXX: convert to IOIN after constant prop
    if size == 1:
      st.expr = Expr(LOAD, [off, SSADef.cur(ctx, reg)])
    elif size == 2:
      st.expr = Expr(LOAD16, [off, SSADef.cur(ctx, reg)])
    elif size == 4:
      st.expr = Expr(LOAD32, [off, SSADef.cur(ctx, reg)])
    else:
      raise InternalError('unhandled size ' + str(size))
    st.dest = [SSADef(ctx, dst)]

  def do_st_abs(reg, addr, size):
    if self.is_io(addr):
      st.op = IMPURE
      if size == 4:
        op = IOOUT32
      elif size == 2:
        op = IOOUT16
      else:
        op = IOOUT
      st.expr = Expr(op, [SSADef.cur(ctx, reg), addr])
      st.expr.dont_propagate = True
      st.expr.dont_eliminate = True
      st.dest = []
    else:
      st.op = ASGN
      st.expr = Expr(VAR, [SSADef.cur(ctx, reg)])
      if size == 4:
        pref = 'Mw'
      elif size == 2:
        pref = 'Mh'
      elif size == 1:
        pref = 'M'
      else:
        raise InternalError('unhandled size ' + str(size))
      st.dest = [SSADef(ctx, pref, addr)]

  def do_st_reg(src, off, reg, size):
    st.dest = []
    st.op = IMPURE
    # XXX: convert to IOOUT after constant prop
    if size == 4:
      op = STORE32
    elif size == 2:
      op = STORE16
    elif size == 1:
      op = STORE
    else:
      raise InternalError('unhandled size ' + str(size))
    st.expr = Expr(op, [SSADef.cur(ctx, src), off, SSADef.cur(ctx, reg)])

  def do_ld_stack(dst, off, size):
    nonlocal sp, st
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, 's', off+sp)])
    st.dest = [SSADef(ctx, dst)]
  
  def do_st_stack(src, off, size):
    nonlocal sp, st
    st.op = ASGN
    st.expr = Expr(VAR, [SSADef.cur(ctx, src)])
    st.dest = [SSADef(ctx, 's', off+sp)]

  def creg(num):
    nonlocal sp
    if num == 13:
      return Expr(AUTO, [sp, -1])
    elif num == 15:
      return insn.addr + 8
    else:
      return SSADef.cur(ctx, 'R'+str(num))

  def get_rm():
    if insn.shift == 0:
      op = SHL
    elif insn.shift == 1:
      op = SHR
    elif insn.shift == 2:
      op = ASR
    else:
      op = ROR
    if insn.shift_rot == 1:
      # rs
      return Expr(op, [creg(insn.rm), creg(insn.rs)])
    else:
      # imm
      return Expr(op, [creg(insn.rm), insn.shift_bits])

  if insn.bytes[0] != OPC_OUTOFRANGE and insn.cond < 0xe or insn.artificial_branch != -1:
    debug(SSA, 5, "conditional", insn, hex(insn.artificial_branch))
    # conditional
    st.op = BRANCH_COND

    if insn.cond == 0:
      st.expr = Expr(VAR, [SSADef.cur(ctx, 'Z')])
    elif insn.cond == 1:
      st.expr = Expr(NOT, [SSADef.cur(ctx, 'Z')])
    elif insn.cond == 2:
      st.expr = Expr(VAR, [SSADef.cur(ctx, 'C')])
    elif insn.cond == 3:
      st.expr = Expr(NOT, [SSADef.cur(ctx, 'C')])
    elif insn.cond == 4:
      st.expr = Expr(VAR, [SSADef.cur(ctx, 'N')])
    elif insn.cond == 5:
      st.expr = Expr(NOT, [SSADef.cur(ctx, 'N')])
    elif insn.cond == 8:
      st.expr = Expr(AND, [SSADef.cur(ctx, 'C'), Expr(NOT, [SSADef.cur(ctx, 'Z')])])
    elif insn.cond == 9:
      st.expr = Expr(OR, [Expr(NOT, [SSADef.cur(ctx, 'C')]), SSADef.cur(ctx, 'Z')])
    elif insn.cond == 0xa:
      st.expr = Expr(COMPARE_EQ, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')])
    elif insn.cond == 0xb:
      st.expr = Expr(COMPARE_NE, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')])
    elif insn.cond == 0xc:
      st.expr = Expr(AND, [
        Expr(NOT, [SSADef.cur(ctx, 'Z')]),
        Expr(COMPARE_EQ, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')])
      ])
    elif insn.cond == 0xd:
      st.expr = Expr(OR, [
        SSADef.cur(ctx, 'Z'),
        Expr(COMPARE_NE, [SSADef.cur(ctx, 'N'), SSADef.cur(ctx, 'V')])
      ])
    else:
      raise InternalError('unsupported condition')

    assert(insn.op & 0xf0 == 0xa0 or insn.artificial_branch != -1)

  if insn.bytes[0] == OPC_OUTOFRANGE:
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['thunk', insn.addr])
  elif insn.cond == 0xf:	# NV predicate
      debug(SSA, 5, "NV predicate")
      st.dest = []
      st.op = ASGN
      st.expr = Expr(NOP, [0])
  elif insn.op & 0xf0 == 0xa0:	# B
      debug(SSA, 5, "branch")
      if insn.cond == 0xe:
        debug(SSA, 5, "unconditional branch")
        st.op = ASGN
        st.dest = []
        st.expr = Expr(NOP, [0])
  elif insn.op & 0xf1 == 0xe0:	# MCR
      debug(SSA, 5, "mcr")
      st.op = IMPURE
      st.dest = []
      st.expr = Expr(INTRINSIC, ['mcr'])
  elif insn.op & 0xf1 == 0xe1:	# MRC
      debug(SSA, 5, "mrc")
      st.op = ASGN
      st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
      st.expr = Expr(INTRINSIC, ['mrc'])
  elif insn.op & 0xc0 == 0x40:	# LDR/STR rd,[rn,+-#imm12 / rm <> shift] pre/post
      if insn.op & 0x20:
        # register offset
        if insn.op & 0x08 == 0x08:
          off = get_rm()
        else:
          off = Expr(SUB, [0, get_rm()])
      else:
        # immediate offset
        if insn.op & 0x08 == 0x08:
          off = insn.imm12
        else:
          off = -insn.imm12
      if insn.op & 0x04 == 0x04:
        size = 1
      else:
        size = 4
      if insn.fixed_mem != -1:
        assert(insn.rn != 13)
        debug(SSA, 6, 'transing fixed mem insn', insn)
        if insn.op & 1:
          do_ld_abs('R'+str(insn.rd), insn.fixed_mem, size)
        else:
          do_st_abs('R'+str(insn.rd), insn.fixed_mem, size)
      elif insn.fixed_stack != -1:
        debug(SSA, 6, 'transing fixed stack insn', insn)
        if insn.op & 1:
          do_ld_stack('R'+str(insn.rd), insn.fixed_stack-sp, size)
        else:
          do_st_stack('R'+str(insn.rd), insn.fixed_stack-sp, size)
      else:
        if insn.op & 1 == 1 and insn.rd == 15:
          # PC load
          if insn.rn == 15:
            # decoded already in insn.py
            st.dest = []
            st.op = ASGN
            st.expr = Expr(NOP, [0])
          else:
            st.dest = []
            st.op = IMPURE
            st.expr = Expr(INTRINSIC, ['set_pc', insn.rn, off])
        else:
          if insn.op & 0x10:	# pre indexing
            noff = off
          else:
            noff = 0
          if insn.rn == 15:
            if insn.op & 1:
              do_ld_abs('R'+str(insn.rd), insn.addr + 8 + noff, size)
            else:
              do_st_abs('R'+str(insn.rd), insn.addr + 8 + noff, size)
          elif insn.rn == 13:
            if insn.op & 1:
              do_ld_stack('R'+str(insn.rd), noff, size)
            else:
              do_st_stack('R'+str(insn.rd), noff, size)
          else:
            if insn.op & 1:
              do_ld_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), size)
            else:
              do_st_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), size)
      if insn.op & 2 == 2 or insn.op & 0x10 == 0:	# write back or post indexing
        if insn.rn == 13:
          sp += off
        else:
          st1 = SSAStatement()
          st.chain(ctx, st1)
          st = st1
          st.op = ASGN
          st.expr = Expr(ADD, [creg(insn.rn), off])
          st.dest = [SSADef(ctx, 'R'+str(insn.rn))]
  elif insn.op & 0xe4 == 4 and insn.imm8 & 0x90 == 0x90:	# LDRH/STRH rd, [rn, +-immWEIRD]
      imm = insn.rm | (insn.rs >> 4)
      if insn.op & 0x08 == 0:
        imm = -imm
      if insn.fixed_mem != -1:
        assert(insn.rn != 13)
        debug(SSA, 6, 'transing fixed mem insn', insn)
        if insn.op & 1:
          do_ld_abs('R'+str(insn.rd), insn.fixed_mem, 2)
        else:
          do_st_abs('R'+str(insn.rd), insn.fixed_mem, 2)
      else:
        if insn.op & 0x10:	# pre indexing
          noff = imm
        else:
          noff = 0
        if insn.rn == 13:
          if insn.op & 1:
            do_ld_stack('R'+str(insn.rd), noff, 2)
          else:
            do_st_stack('R'+str(insn.rd), noff, 2)
        else:
          if insn.op & 1:
            do_ld_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), 2)
          else:
            do_st_reg('R'+str(insn.rd), noff, 'R'+str(insn.rn), 2)
      if insn.op & 2:	# write back
        st1 = SSAStatement()
        st.chain(ctx, st1)
        st = st1
        st.op = ASGN
        st.expr = Expr(ADD, [creg(insn.rn), imm])
        st.dest = [SSADef(ctx, 'R'+str(insn.rn))]
  elif insn.op == 0x32:	# MSR CPSR_f, rm
      debug(SSA, 5, "MSR CPSR_f, rm")
      st.op = IMPURE
      st.dest = []
      st.expr = Expr(INTRINSIC, ['msr_cpsr_f', creg(insn.rm)])
  elif insn.bytes[0] & 0x0fbf0fff == 0x010f0000:	# MRS
      st.op = ASGN
      st.expr = Expr(INTRINSIC, ['mrs', insn.op & 4])
      st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
  elif insn.bytes[0] & 0x0fbffff0 == 0x0129f000:	# MSR
      st.op = IMPURE
      st.expr = Expr(INTRINSIC, ['msr', insn.op & 4, creg(insn.rm)])
      st.dest = []
  elif insn.op & 0xf0 == 0xb0:	# BL off24
    st.expr = Expr(ARGS, [insn.addr + 8 + insn.off24 * 4] + self.fun_args(ctx, insn.next[1], st, sp))
    st.dest = self.fun_returns(ctx, insn.next[1], st)
    st.op = CALL
  elif insn.op & 0xe0 == 0x80:	# LDM/STM
    # XXX: PSR/force user?
    off = 0
    if insn.op & 0x08 == 0x08:
      inc = 4
      regs = range(0, 16)
    else:
      inc = -4
      regs = range(15, -1, -1)
    st.op = None
    do_return = False
    for i in regs:
      if insn.reglist & (1 << i):
        if insn.op & 0x10 == 0x10:	# pre indexing
          off += inc
        if st.op != None:
          st1 = SSAStatement()
          st.chain(ctx, st1)
          st = st1
        if insn.op & 1:	# LDM
          if i == 15:
            # XXX: only if [rn,off] is r14
            do_return = True
          elif insn.rn == 13:
            do_ld_stack('R'+str(i), off, 4)
          else:
            do_ld_reg('R'+str(i), off, 'R'+str(insn.rn), 4)
        else:
          if insn.rn == 13:
            do_st_stack('R'+str(i), off, 4)
          else:
            do_st_reg('R'+str(i), off, 'R'+str(insn.rn), 4)
        if insn.op & 0x10 != 0x10:	# post indexing
          off += inc
    if insn.op & 2 == 2:	# write back
        if insn.rn == 13:
          sp += off
          if end_bp == 0:
            end_bp = sp
        else:
          if st.op != None:
            st1 = SSAStatement()
            st.chain(ctx, st1)
            st = st1
          st.op = ASGN
          st.expr = Expr(ADD, [creg(insn.rn), off])
          st.dest = [SSADef(ctx, 'R'+str(insn.rn))]
    if do_return:
      if st.op != None:
        st1 = SSAStatement()
        st.chain(ctx, st1)
        st = st1
      st.op = RETURN
      st.expr = None
      st.dest = []
  elif insn.bytes[0] & 0x0ffffff0 == 0x012fff10:	# BX rm
    if insn.rm == 14:
      # XXX: only if R14 is unassigned
      st.dest = []
      st.op = RETURN
      st.expr = None
    else:
      st.dest = []
      st.op = IMPURE
      st.expr = Expr(INTRINSIC, ['bx', creg(insn.rm)])
      st.add_comment('XXX: indirect jump not implemented yet')
  elif insn.bytes[0] & 0xffffff0 == 0x012fff30:	# BLX rm
    st.dest = []
    st.op = IMPURE
    st.expr = Expr(INTRINSIC, ['blx', creg(insn.rm)])
    st.add_comment('XXX: indirect call not implemented yet')
  elif insn.bytes[0] & 0x0f900090 == 0x01000080:	# smul/smla
    op = (insn.op >> 1) & 3
    x = (insn.imm8 >> 5) & 1
    y = (insn.imm8 >> 6) & 1
    if op == 0 or op == 3:
      m1 = creg(insn.rm)
      m2 = creg(insn.rs)
      if x == 0:
        m1 = Expr(AND, [m1, 0xffff])
      else:
        m1 = Expr(SHR, [m1, 16])
      if y == 0: 
        m2 = Expr(AND, [m2, 0xffff])
      else:
        m2 = Expr(SHR, [m2, 16])
      st.op = ASGN
      st.expr = Expr(MUL32, [m1, m2])
      if op == 0:	# smla
        st.expr = Expr(ADD, [st.expr, creg(insn.rn)])
      st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
    else:
      debug(SSA, 2, "unimplemented smul", insn)
      st.op = ASGN
      st.expr = Expr(INTRINSIC, ["smulw", op, x, y, creg(insn.rm), creg(insn.rs)])
      st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
  elif insn.bytes[0] & 0x0e000010 == 0x06000010:	# media insn
      # XXX: untested, implemented inadvertently
      debug(SSA, 2, "unimplemented media instruction", insn)
      st.op = ASGN
      st.expr = Expr(INTRINSIC, ["media_insn", insn.bytes[0], creg(insn.rm)])
      st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
  elif insn.bytes[0] & 0x0f9000f0 == 0x01000050:	# sat add/sub
      debug(SSA, 2, "unimplemented saturated add/sub", insn)
      st.op = ASGN
      st.expr = Expr(INTRINSIC, ["qaddsub", insn.bytes[0], creg(insn.rn), creg(insn.rm)])
      st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
  elif insn.op & 0xc0 == 0x00:	# ALU rd, rn, #imm8 <> rs / rm <> shift
      alu_op = (insn.op >> 1) & 0xf
      debug(SSA, 5, "alu op", alu_op)
      if insn.rd == 13 and alu_op in [2, 4]:
        assert(insn.op & 0x20 == 0x20)	# immediate
        if alu_op == 4:
          # XXX: hack: assume conditional adds to SP only occur in epilogs and ignore them
          # otherwise our stack pointer tracking gets mangled
          if insn.cond == 0xe:
            sp += rot_imm(insn.imm8, insn.rs)
        else:
          sp -= rot_imm(insn.imm8, insn.rs)
        st.op = ASGN
        st.dest = []
        st.expr = Expr(NOP, [sp])
      else:
        st.op = None
        if insn.op & 0x20 == 0:
          imm = get_rm()
        else:
          imm = rot_imm(insn.imm8, insn.rs)

        if alu_op in [2, 3, 6, 7, 0xa]:
          op = SUB
          op_c = COMPARE_GE
          op_z = COMPARE_EQ
          op_n = COMPARE_LT
          op_v = SUBFLAGS_V
        elif alu_op == 0 or alu_op == 8 or alu_op == 0xe:
          op = AND
          op_c = ANDFLAGS_C
          op_z = ANDFLAGS_Z
          op_n = ANDFLAGS_N
          op_v = None
        elif alu_op == 1 or alu_op == 9:
          op = EOR
          op_c = EORFLAGS_C
          op_z = EORFLAGS_Z
          op_n = EORFLAGS_N
          op_v = None
        elif alu_op == 4 or alu_op == 5 or alu_op == 0xb:
          op = ADD
          op_c = ADDFLAGS_C
          op_z = ADDFLAGS_Z
          op_n = ADDFLAGS_N
          op_v = ADDFLAGS_V
        elif alu_op == 0xc:
          op = OR
          op_c = ORFLAGS_C
          op_z = ORFLAGS_Z
          op_n = ORFLAGS_N
          op_v = None
        else:	# MOV, MVN
          op = CONST
          op_c = MOVFLAGS_C
          op_z = MOVFLAGS_Z
          op_n = MOVFLAGS_N
          op_v = None

        reverse = False
        if alu_op == 3 or alu_op == 7:	# RSB, RSC
          reverse = True

        if alu_op == 0xf or alu_op == 0xe:	# BIC, MVN
          imm = Expr(INV, [imm])

        if op == CONST:
          if insn.op & 0x20 == 0:
            st.expr = imm
          else:
            st.expr = Expr(CONST, [imm])
        else:
          if insn.rn == 13 and insn.op & 0x20 == 0x20 and alu_op == 4:
            st.expr = Expr(AUTO, [sp + imm, -1])
            # XXX: may be better to do this on CALL
            if sp + imm < bp:
              bp = sp + imm
          elif insn.rn == 13 and insn.op & 0x20 == 0x20 and alu_op == 2:
            st.expr = Expr(AUTO, [sp - imm, -1])
            if sp - imm < bp:
              bp = sp - imm
          else:
            op1 = creg(insn.rn)
            if reverse:
              op2 = op1
              op1 = imm
            else:
              op2 = imm

            if alu_op == 5:	# ADC
              st.expr = Expr(op, [op1, op2, SSADef.cur(ctx, 'C')])
            elif alu_op == 6 or alu_op == 7:	# SBC, RSC
              st.expr = Expr(ADD, [Expr(op, [op1, op2, 1]), SSADef.cur(ctx, 'C')])
            else:
              st.expr = Expr(op, [op1, op2])

        if alu_op in [0, 1, 2, 3, 4, 5, 6, 7, 0xc, 0xd, 0xe, 0xf] and insn.rd != 15:
          st.op = ASGN
          st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
        if insn.rd == 15:
          st.op = IMPURE
          st.expr = Expr(INTRINSIC, ['set_pc', st.expr])
          st.dest = []

        if alu_op == 0xb and not (insn.op & 1):
          # clz
          # XXX: complete guesswork, too lazy too look it up
          st.op = ASGN
          st.expr = Expr(INTRINSIC, ['clz', creg(insn.rn)])
          st.dest = [SSADef(ctx, 'R'+str(insn.rd))]
        elif insn.op & 1:	# set flags
          alu_expr = st.expr
          if st.op == ASGN:
            st1 = SSAStatement()
            st.chain(ctx, st1)
            st = st1
          st.op = ASGN
          st.expr = Expr(op_c, copy(alu_expr.ops))
          st.dest = [SSADef(ctx, 'C')]
          st1 = SSAStatement()
          st.chain(ctx, st1)
          st = st1
          st.op = ASGN
          st.expr = Expr(op_z, copy(alu_expr.ops))
          st.dest = [SSADef(ctx, 'Z')]
          st1 = SSAStatement()
          st.chain(ctx, st1)
          st = st1
          st.op = ASGN
          st.expr = Expr(op_n, copy(alu_expr.ops))
          st.dest = [SSADef(ctx, 'N')]
          if op_v:
            st1 = SSAStatement()
            st.chain(ctx, st1)
            st = st1
            st.op = ASGN
            st.expr = Expr(op_v, copy(alu_expr.ops))
            st.dest = [SSADef(ctx, 'V')]
          
        
  else:
    raise InternalError('unknown op ' + hex(insn.op))

  # all current indices are reaching, with the exception of anything
  # below the stack pointer
  st.reaching = []
  for i in ctx.local_indices.values():
    if not (i.type == 's' and i.addr < 0): #True: #i.type != 's':# or i.addr > sp:
      st.reaching += [i]

  self.last_ssa_for_insn[insn] = st
  debug(SSA, 6, "st_end in translate", st)
  return (st_start, st, sp, bp, end_bp, next)