2128 lines
77 KiB
Python
2128 lines
77 KiB
Python
import copy
|
|
import logging
|
|
from . util import *
|
|
import sys
|
|
|
|
class instruction(object):
|
|
def __init__(self, opcode_args, n_operands, string, tstates=1):
|
|
self.string = string
|
|
self.super_op = 0
|
|
#op_args = []
|
|
#for i in opcode_args:
|
|
##super_op = i[0] >> 8
|
|
##self.super_op = super_op
|
|
##op = i[0] & 255
|
|
#op_args.append((op, i[1]))
|
|
#self.opcode_args = op_args
|
|
self.opcode_args = opcode_args
|
|
|
|
self.n_operands = n_operands # number bytes to read pos opcodeaa()
|
|
self.tstates = tstates
|
|
|
|
def __call__(self, f):
|
|
return Instruction(self, f)
|
|
|
|
|
|
class Instruction(object):
|
|
def __init__(self, ins, executer):
|
|
self.string = ins.string
|
|
self.super_op = ins.super_op
|
|
self.opcode_args = ins.opcode_args
|
|
self.n_operands = ins.n_operands
|
|
self.tstates = ins.tstates
|
|
self.executer = executer
|
|
|
|
def get_read_list(self, operands=()):
|
|
return self.executer(*((self, self.registers, True, None) + self.args +
|
|
tuple([operands[i] for i in self.operands]) ))
|
|
|
|
def execute(self, data=None, operands=()):
|
|
return self.executer(*((self, self.registers, False, data) + self.args +
|
|
tuple([operands[i] for i in self.operands]) ))
|
|
|
|
def assembler(self, operands=()):
|
|
return self.string.format(*(self.args + tuple([operands[i] for i in self.operands])))
|
|
|
|
|
|
def __str__(self):
|
|
s = "Instruction: " + self.string + "\n"
|
|
s += "args: " + str(self.args) + "\n"
|
|
s += "operand bytes: " + str(self.operands) + "\n"
|
|
return s
|
|
|
|
|
|
class InstructionSet():
|
|
|
|
def __init__(self, registers):
|
|
self._registers = registers
|
|
|
|
self._instructions = {} #0: [None] * 256} #keys of this are super_ops
|
|
|
|
self._instructions2 = {}
|
|
# Fill instruction lookup
|
|
for i in dir(self):
|
|
f = getattr(self, i)
|
|
if f.__class__ == Instruction:
|
|
print (i, ":")
|
|
for o in f.opcode_args:
|
|
print (o)
|
|
ff = copy.copy(f)
|
|
ff.registers = self._registers
|
|
ff.args = o[1]
|
|
if len(o) == 3:
|
|
ff.tstates = o[2]
|
|
#print "Tstates=", ff.tstates
|
|
else:
|
|
# print "missing tstates for "
|
|
# tstates not specified so used instruction group number
|
|
# so default...
|
|
pass
|
|
ff.operands = []
|
|
d = self._instructions2
|
|
opargs = o
|
|
if type(o[0]) == type(0x4):
|
|
if o[0] > 0xFF:
|
|
opargs = ((o[0] >> 8, o[0] & 0xFF), o[1])
|
|
else:
|
|
opargs = ((o[0], ), o[1])
|
|
for n, i in enumerate(opargs[0][:-1]):
|
|
if i in d:
|
|
d = d[i]
|
|
elif i == "-":
|
|
ff.operands.append(n)
|
|
if len(d.keys()) == 0:
|
|
d2 = {}
|
|
for i in range(256):
|
|
d[i] = d2
|
|
d = d2
|
|
else:
|
|
d = d[0]
|
|
else:
|
|
d[i] = {}
|
|
d = d[i]
|
|
if opargs[0][-1] == "-":
|
|
ff.operands.append(n+1)
|
|
for i in range(256):
|
|
d[i] = ff
|
|
else:
|
|
d[opargs[0][-1]] = ff
|
|
|
|
|
|
|
|
self._instructions = self._instructions2
|
|
|
|
self._instruction_composer = []
|
|
self._composer_instruction = None
|
|
self._composer_len = 1
|
|
|
|
|
|
def __getitem__(self, ins):
|
|
if self.is_two_parter(ins):
|
|
return self._instructions[ins]
|
|
else:
|
|
if ins in self._instructions[0]:
|
|
return self._instructions[0][ins]
|
|
raise AttributeError("Unknown opcode")
|
|
|
|
def __lshift__(self, op):
|
|
self._instruction_composer.append(op)
|
|
q = self._instructions
|
|
for i in self._instruction_composer:
|
|
q = q[i]
|
|
if isinstance(q, dict):
|
|
return False, 0
|
|
else:
|
|
ops = tuple(self._instruction_composer)
|
|
self._instruction_composer = []
|
|
# print q, ops
|
|
return q, ops
|
|
|
|
def reset_composer(self):
|
|
self._instruction_composer = []
|
|
|
|
def is_two_parter(self, ins):
|
|
return ins in self._instructions
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
#----------------------------------------------------------------------
|
|
# 8-bit Load Instructions
|
|
#----------------------------------------------------------------------
|
|
@instruction([(0x7F, ("A", "A")), (0x78, ("A", "B")), (0x79, ("A", "C")), (0x7A, ("A", "D")), (0x7B, ("A", "E")),
|
|
(0x7C, ("A", "H")), (0x7D, ("A", "L")),
|
|
(0x47, ("B", "A")), (0x40, ("B", "B")), (0x41, ("B", "C")), (0x42, ("B", "D")), (0x43, ("B", "E")),
|
|
(0x44, ("B", "H")), (0x45, ("B", "L")),
|
|
(0x4F, ("C", "A")), (0x48, ("C", "B")), (0x49, ("C", "C")), (0x4A, ("C", "D")), (0x4B, ("C", "E")),
|
|
(0x4C, ("C", "H")), (0x4D, ("C", "L")),
|
|
(0x57, ("D", "A")), (0x50, ("D", "B")), (0x51, ("D", "C")), (0x52, ("D", "D")), (0x53, ("D", "E")),
|
|
(0x54, ("D", "H")), (0x55, ("D", "L")),
|
|
(0x5F, ("E", "A")), (0x58, ("E", "B")), (0x59, ("E", "C")), (0x5A, ("E", "D")), (0x5B, ("E", "E")),
|
|
(0x5C, ("E", "H")), (0x5D, ("E", "L")),
|
|
(0x67, ("H", "A")), (0x60, ("H", "B")), (0x61, ("H", "C")), (0x62, ("H", "D")), (0x63, ("H", "E")),
|
|
(0x64, ("H", "H")), (0x65, ("H", "L")),
|
|
(0x6F, ("L", "A")), (0x68, ("L", "B")), (0x69, ("L", "C")), (0x6A, ("L", "D")), (0x6B, ("L", "E")),
|
|
(0x6C, ("L", "H")), (0x6D, ("L", "L")),
|
|
(0xED47, ("I", "A"), 9), (0xED4F, ("R", "A"), 9),
|
|
], 0, "LD {0}, {1}", 4)
|
|
def ld_r_r_(instruction, registers, get_reads, data, r, r_):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = registers[r_]
|
|
return []
|
|
|
|
@instruction([(0xED57, ('I', )), (0xED5F, ("R", ))], 0, "LD A, {0}", 9)
|
|
def ld_a_ir(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if r == "R":
|
|
# Add 2 to refresh. TODO: fix
|
|
registers[r] += 2
|
|
registers.A = registers[r]
|
|
registers.condition.S = registers[r] >> 7
|
|
registers.condition.Z = registers[r] == 0
|
|
registers.condition.H = 0
|
|
registers.condition.PV = registers.IFF2
|
|
registers.condition.N = 0
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
#@instruction([(0xED47, ("I", )), (0xED5F, ("R", )), (0x00, (), 30) ],
|
|
#1, "LD {0}, {1}", 9)
|
|
#def ld_a_ir(instruction, registers, get_reads, data, r):
|
|
#if get_reads:
|
|
#return []
|
|
#else:
|
|
##registers.A = registers[r]
|
|
##registers.condition.S = registers[r] >> 7
|
|
##registers.condition.Z = registers[r] == 0
|
|
##registers.condition.H = 0
|
|
##registers.condition.PV = registers.IFF2
|
|
##registers.condition.N = 0
|
|
##set_f5_f3_from_a(registers)
|
|
#return []
|
|
|
|
|
|
|
|
@instruction([([0x3E, '-'], ("A", )), ([0x06, '-'], ("B", )), ([0x0E, '-'], ("C", )),
|
|
([0x16, '-'], ("D", )), ([0x1E, '-'], ("E", )), ([0x26, '-'], ("H", )),
|
|
([0x2E, '-'], ("L", ))],
|
|
1, "LD {0}, {1:X}H", 7)
|
|
def ld_r_n(instruction, registers, get_reads, data, r, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = n
|
|
return []
|
|
|
|
|
|
@instruction([(0x7E, ("A", )), (0x46, ("B", )), (0x4E, ("C", )), (0x56, ("D", )), (0x5E, ("E", )), (0x66, ("H", )),
|
|
(0x6E, ("L", ))],
|
|
0, "LD {0}, (HL)", 7)
|
|
def ld_r_hl(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return [registers.H << 8 | registers.L]
|
|
else:
|
|
registers[r] = data[0]
|
|
return []
|
|
|
|
@instruction([([0xDD, 0x7E, '-'], ("A", "IX")), ([0xDD, 0x46, '-'], ("B", "IX")),
|
|
([0xDD, 0x4E, '-'], ("C", "IX")), ([0xDD, 0x56, '-'], ("D", "IX")),
|
|
([0xDD, 0x5E, '-'], ("E", "IX")), ([0xDD, 0x66, '-'], ("H", "IX")),
|
|
([0xDD, 0x6E, '-'], ("L", "IX")),
|
|
([0xFD, 0x7E, '-'], ("A", "IY")), ([0xFD, 0x46, '-'], ("B", "IY")),
|
|
([0xFD, 0x4E, '-'], ("C", "IY")), ([0xFD, 0x56, '-'], ("D", "IY")),
|
|
([0xFD, 0x5E, '-'], ("E", "IY")), ([0xFD, 0x66, '-'], ("H", "IY")),
|
|
([0xFD, 0x6E, '-'], ("L", "IY"))],
|
|
1, "LD {0}, ({1}+{2:X}H)", 19)
|
|
def ld_r_i_d(instruction, registers, get_reads, data, r, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
registers[r] = data[0]
|
|
return []
|
|
|
|
@instruction([(0x77, ("A", )), (0x70, ("B", )), (0x71, ("C", )), (0x72, ("D", )), (0x73, ("E", )), (0x74, ("H", )),
|
|
(0x75, ("L", ))],
|
|
0, "LD (HL), {0}", 7)
|
|
def ld_hl_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return [(registers.H << 8 | registers.L, registers[r])]
|
|
|
|
@instruction([([0xDD, 0x77, '-'], ("A", "IX")), ([0xDD, 0x70, '-'], ("B", "IX")),
|
|
([0xDD, 0x71, '-'], ("C", "IX")), ([0xDD, 0x72, '-'], ("D", "IX")),
|
|
([0xDD, 0x73, '-'], ("E", "IX")), ([0xDD, 0x74, '-'], ("H", "IX")),
|
|
([0xDD, 0x75, '-'], ("L", "IX")),
|
|
([0xFD, 0x77, '-'], ("A", "IY")), ([0xFD, 0x70, '-'], ("B", "IY")),
|
|
([0xFD, 0x71, '-'], ("C", "IY")), ([0xFD, 0x72, '-'], ("D", "IY")),
|
|
([0xFD, 0x73, '-'], ("E", "IY")), ([0xFD, 0x74, '-'], ("H", "IY")),
|
|
([0xFD, 0x75, '-'], ("L", "IY"))],
|
|
1, "LD ({1}+{2:X}H), {0}", 19)
|
|
def ld_i_d_r(instruction, registers, get_reads, data, r, i, d):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return [( registers[i] + get_8bit_twos_comp(d), registers[r])]
|
|
|
|
@instruction([([0x36, '-'], ( ))], 1, "LD (HL), {0:X}H", 10)
|
|
def ld_hl_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return [(registers.H << 8 | registers.L, n)]
|
|
|
|
@instruction([([0xDD, 0x36, '-', '-'], ("IX", )), ([0xFD, 0x36, '-', '-'], ("IY", ))],
|
|
2, "LD ({0}+{1:X}H), {2:X}H", 19)
|
|
def ld_i_d_n(instruction, registers, get_reads, data, i, d, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return [( registers[i] + get_8bit_twos_comp(d), n)]
|
|
|
|
@instruction([(0x0A, ("B", "C")), (0x1A, ("D", "E"))],
|
|
0, "LD A, ({0}{1})", 7)
|
|
def ld_a_rr(instruction, registers, get_reads, data, r, r2):
|
|
if get_reads:
|
|
return [registers[r] << 8 | registers[r2]]
|
|
else:
|
|
registers.A = data[0]
|
|
return []
|
|
|
|
@instruction([([0x3A, '-', '-'], ())],
|
|
2, "LD A, ({1:x}{0:X}H)", 13)
|
|
def ld_a_nn(instruction, registers, get_reads, data, n, n2):
|
|
if get_reads:
|
|
return [n2 << 8 | n]
|
|
else:
|
|
registers.A = data[0]
|
|
return []
|
|
|
|
|
|
@instruction([(0x02, ("B", "C")), (0x12, ("D", "E"))],
|
|
0, "LD ({0}{1}), A", 7)
|
|
def ld_rr_a(instruction, registers, get_reads, data, r, r2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return [(registers[r] << 8 | registers[r2], registers.A)]
|
|
|
|
|
|
@instruction([([0x32, '-', '-'], ())],
|
|
2, "LD ({1:x}{0:X}H), A", 13)
|
|
def ld_nn_a(instruction, registers, get_reads, data, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return [(n2 << 8 | n, registers.A)]
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
# 16-bit Load instructions
|
|
#----------------------------------------------------------------------
|
|
@instruction([([0x01, '-', '-'], ("B", "C")), ([0x11, '-', '-'], ("D", "E")), ([0x21, '-', '-'], ("H", "L"))],
|
|
2, "LD {0}{1}, {3:X}{2:X}H", 10)
|
|
def ld_dd_nn(instruction, registers, get_reads, data, r, r2, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = n2
|
|
registers[r2] = n
|
|
return []
|
|
|
|
@instruction([([0x31, '-', '-'], ("SP",), 10), ([0xDD, 0x21, '-', '-'], ("IX", )),
|
|
([0xFD, 0x21, '-', '-'], ("IY", ))],
|
|
2, "LD {0}, {2:X}{1:X}H", 14)
|
|
def ld_D_nn(instruction, registers, get_reads, data, r, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = n2 << 8 | n
|
|
return []
|
|
|
|
@instruction([([0xED, 0x4B, '-', '-'], ("B", "C" )), ([0xED, 0x5B, '-', '-'], ("D", "E" )),
|
|
([0xED, 0x6B, '-', '-'], ("H", "L" )), ([0x2A, '-', '-'], ("H", "L" ), 16), ],
|
|
2, "LD {0}{1}, ({3:X}{2:X}H)", 20)
|
|
def ld_dd_nn_(instruction, registers, get_reads, data, r, r_, n, n_):
|
|
if get_reads:
|
|
return [n_ << 8 | n, (n_ << 8 | n) + 1]
|
|
else:
|
|
registers[r] = data[1]
|
|
registers[r_] = data[0]
|
|
return []
|
|
|
|
@instruction([([0xDD, 0x2A, '-', '-'], ("IX", )), ([0xFD, 0x2A, '-', '-'], ("IY", )),
|
|
([0xED, 0x7B, '-', '-'], ("SP", ))],
|
|
2, "LD {0}, ({2:X}{1:X}H)", 20)
|
|
def ld_D_nn_(instruction, registers, get_reads, data, r, n, n2):
|
|
if get_reads:
|
|
return [n2 << 8 | n, (n2 << 8 | n) + 1]
|
|
else:
|
|
registers[r] = data[1] << 8 | data[0]
|
|
return []
|
|
|
|
|
|
@instruction([([0xED, 0x73, '-', '-'], ("SP", )), ([0xDD, 0x22, '-', '-'], ("IX", )),
|
|
([0xFD, 0x22, '-', '-'], ("IY", ))],
|
|
2, "LD ({2:X}{1:X}H), {0}", 20)
|
|
def ld_nn__D(instruction, registers, get_reads, data, r, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
ad = n2 << 8 | n
|
|
return [(ad + 1, registers[r] >> 8),
|
|
(ad, registers[r] & 255)]
|
|
|
|
@instruction([([0xED, 0x63, '-', '-'], ("H", "L", )), ([0x22, '-', '-'], ("H", "L", ), 16),
|
|
([0xED, 0x43, '-', '-'], ("B", "C", )), ([0xED, 0x53, '-', '-'], ("D", "E", ))],
|
|
2, "LD ({3:X}{2:X}H), {0}{1}", 20)
|
|
def ld_nn_D(instruction, registers, get_reads, data, r, r2, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
ad = n2 << 8 | n
|
|
return [(ad + 1, registers[r]),
|
|
(ad, registers[r2])]
|
|
|
|
@instruction([(0xF9, ())],
|
|
0, "LD SP, HL", 6)
|
|
def ld_sp_hl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.SP = registers.H << 8 | registers.L
|
|
return []
|
|
|
|
@instruction([(0xDDF9, ("IX", )), (0xFDF9, ("IY", ))],
|
|
0, "LD SP, {0}", 10)
|
|
def ld_sp_i(instruction, registers, get_reads, data, i):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.SP = registers[i]
|
|
return []
|
|
|
|
|
|
@instruction([(0xC5, ("B", "C" )), (0xD5, ("D", "E" )), (0xE5, ("H", "L" )), (0xF5, ("A", "F" ))],
|
|
0, "PUSH {0}{1}", 11)
|
|
def push_qq(instruction, registers, get_reads, data, q, q2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
stack = registers.SP
|
|
registers.SP -= 2
|
|
return [(stack - 1, registers[q]), (stack - 2, registers[q2])]
|
|
|
|
|
|
@instruction([(0xDDE5, ("IX", )), (0xFDE5, ("IY", ))],
|
|
0, "PUSH {0}", 15)
|
|
def push_i(instruction, registers, get_reads, data, i):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
stack = registers.SP
|
|
registers.SP -= 2
|
|
return [(stack - 1, registers[i] >> 8), (stack - 2, registers[i] & 255)]
|
|
|
|
|
|
@instruction([(0xC1, ("B", "C" )), (0xD1, ("D", "E" )), (0xE1, ("H", "L" )), (0xF1, ("A", "F" ))],
|
|
0, "POP {0}{1}", 10)
|
|
def pop_qq(instruction, registers, get_reads, data, q, q2):
|
|
if get_reads:
|
|
stack = registers.SP
|
|
return [stack, stack + 1]
|
|
else:
|
|
registers.SP += 2
|
|
registers[q2] = data[0]
|
|
registers[q] = data[1]
|
|
return []
|
|
|
|
|
|
@instruction([(0xDDE1, ("IX", )), (0xFDE1, ("IY", ))],
|
|
0, "POP {0}", 14)
|
|
def pop_i(instruction, registers, get_reads, data, i):
|
|
if get_reads:
|
|
stack = registers.SP
|
|
return [stack, stack + 1]
|
|
else:
|
|
registers.SP += 2
|
|
registers[i] = data[1] << 8 | data[0]
|
|
return []
|
|
|
|
#----------------------------------------------------------------------
|
|
# Exchange, Block Transfer, and Search Group
|
|
#----------------------------------------------------------------------
|
|
@instruction([(0xEB, ())], 0, "EX DE, HL", 4)
|
|
def ex_de_hl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.D, registers.H = (registers.H, registers.D)
|
|
registers.E, registers.L = (registers.L, registers.E)
|
|
return []
|
|
|
|
@instruction([(0x08, ())], 0, "EX AF, AF'", 4)
|
|
def ex_af_af_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A, registers.A_ = (registers.A_, registers.A)
|
|
registers.F, registers.F_ = (registers.F_, registers.F)
|
|
return []
|
|
|
|
@instruction([(0xD9, ())], 0, "EXX", 4)
|
|
def exx(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.B, registers.B_ = (registers.B_, registers.B)
|
|
registers.C, registers.C_ = (registers.C_, registers.C)
|
|
registers.D, registers.D_ = (registers.D_, registers.D)
|
|
registers.E, registers.E_ = (registers.E_, registers.E)
|
|
registers.H, registers.H_ = (registers.H_, registers.H)
|
|
registers.L, registers.L_ = (registers.L_, registers.L)
|
|
return []
|
|
|
|
@instruction([(0xE3, ())], 0, "EX (SP), HL", 19)
|
|
def ex_sp__hl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.SP, registers.SP + 1]
|
|
else:
|
|
h = registers.H
|
|
l = registers.L
|
|
registers.H = data[1]
|
|
registers.L = data[0]
|
|
return [(registers.SP, l), (registers.SP + 1, h)]
|
|
|
|
@instruction([(0xDDE3, ("IX", )), (0xFDE3, ("IY", ))], 0,
|
|
"EX (SP), {0}", 23)
|
|
def ex_sp__i(instruction, registers, get_reads, data, i):
|
|
if get_reads:
|
|
return [registers.SP, registers.SP + 1]
|
|
else:
|
|
ix = registers[i]
|
|
registers[i] = data[1] << 8 | data[0]
|
|
|
|
return [(registers.SP, registers[i] & 255),
|
|
(registers.SP + 1, registers[i] >> 8)]
|
|
|
|
@instruction([(0xEDA0, ())], 0, "LDI", 16)
|
|
def ldi(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.H << 8 | registers.L]
|
|
|
|
else:
|
|
de_ = de = registers.D << 8 | registers.E
|
|
hl = registers.H << 8 | registers.L
|
|
bc = registers.B << 8 | registers.C
|
|
hl += 1
|
|
if hl > 0xFFFF: hl = 0
|
|
registers.H = hl >> 8
|
|
registers.L = hl & 0xFF
|
|
bc -= 1
|
|
if bc < 0: bc = 0xFFFF
|
|
registers.B = bc >> 8
|
|
registers.C = bc & 0xFF
|
|
de += 1
|
|
if de > 0xFFFF: de = 0
|
|
registers.D = de >> 8
|
|
registers.E = de & 0xFF
|
|
|
|
registers.condition.H = 0
|
|
if bc != 0:
|
|
registers.condition.PV = 1
|
|
else:
|
|
registers.condition.PV = 0
|
|
registers.condition.N = 0
|
|
registers.condition.F3 = (registers.A + data[0]) & 0x08
|
|
registers.condition.F5 = (registers.A + data[0]) & 0x02
|
|
return [(de, data[0])]
|
|
|
|
@instruction([(0xEDB0, ())], 0, "LDIR", 21)
|
|
def ldir(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.H << 8 | registers.L]
|
|
else:
|
|
de_ = de = registers.D << 8 | registers.E
|
|
hl = registers.H << 8 | registers.L
|
|
bc = registers.B << 8 | registers.C
|
|
hl += 1
|
|
if hl > 0xFFFF: hl = 0
|
|
registers.H = hl >> 8
|
|
registers.L = hl & 0xFF
|
|
bc -= 1
|
|
if bc < 0: bc = 0xFFFF
|
|
registers.B = bc >> 8
|
|
registers.C = bc & 0xFF
|
|
de += 1
|
|
if de > 0xFFFF: de = 0
|
|
registers.D = de >> 8
|
|
registers.E = de & 0xFF
|
|
|
|
registers.condition.H = 0
|
|
if bc != 0:
|
|
registers.PC -= 2
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
|
|
registers.condition.PV = 0
|
|
registers.condition.N = 0
|
|
registers.condition.F3 = (registers.A + data[0]) & 0x08
|
|
registers.condition.F5 = (registers.A + data[0]) & 0x02
|
|
return [(de, data[0])]
|
|
|
|
|
|
@instruction([(0xEDA8, ())], 0, "LDD", 16)
|
|
def ldd(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.H << 8 | registers.L]
|
|
else:
|
|
de_ = de = registers.D << 8 | registers.E
|
|
hl = registers.H << 8 | registers.L
|
|
bc = registers.B << 8 | registers.C
|
|
hl -= 1
|
|
if hl < 0: hl = 0xFFFF
|
|
registers.H = hl >> 8
|
|
registers.L = hl & 0xFF
|
|
bc -= 1
|
|
if bc < 0: bc = 0xFFFF
|
|
registers.B = bc >> 8
|
|
registers.C = bc & 0xFF
|
|
de -= 1
|
|
if de < 0: de = 0xFFFF
|
|
registers.D = de >> 8
|
|
registers.E = de & 0xFF
|
|
|
|
registers.condition.H = 0
|
|
if bc != 0:
|
|
registers.condition.PV = 1
|
|
else:
|
|
registers.condition.PV = 0
|
|
registers.condition.N = 0
|
|
registers.condition.F3 = (registers.A + data[0]) & 0x08
|
|
registers.condition.F5 = (registers.A + data[0]) & 0x02
|
|
return [(de, data[0])]
|
|
|
|
@instruction([(0xEDB8, ())], 0, "LDDR", 16)
|
|
def lddr(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.H << 8 | registers.L]
|
|
else:
|
|
de_ = de = registers.D << 8 | registers.E
|
|
hl = registers.H << 8 | registers.L
|
|
bc = registers.B << 8 | registers.C
|
|
hl -= 1
|
|
if hl < 0: hl = 0xFFFF
|
|
registers.H = hl >> 8
|
|
registers.L = hl & 0xFF
|
|
bc -= 1
|
|
if bc < 0: bc = 0xFFFF
|
|
registers.B = bc >> 8
|
|
registers.C = bc & 0xFF
|
|
de -= 1
|
|
if de < 0: de = 0xFFFF
|
|
registers.D = de >> 8
|
|
registers.E = de & 0xFF
|
|
|
|
registers.condition.H = 0
|
|
if bc != 0:
|
|
registers.PC -= 2
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
|
|
registers.condition.PV = 0
|
|
registers.condition.N = 0
|
|
registers.condition.F3 = (registers.A + data[0]) & 0x08
|
|
registers.condition.F5 = (registers.A + data[0]) & 0x02
|
|
return [(de, data[0])]
|
|
|
|
|
|
@instruction([(0xEDA1, ())], 0, "CPI", 16)
|
|
def cpi(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.HL = inc16(registers.HL)
|
|
registers.BC = dec16(registers.BC)
|
|
|
|
subtract8(registers.A, data[0], registers)
|
|
registers.condition.PV = registers.BC != 0
|
|
# F3 is bit 3 of (A - (HL) - H), H
|
|
# F5 is bit 1 of (A - (HL) - H), H a
|
|
f5f3 = registers.A - data[0] - registers.H
|
|
registers.condition.F5 = f5f3 & 0x01
|
|
registers.condition.F3 = f5f3 & 0x04
|
|
return []
|
|
|
|
@instruction([(0xEDB1, ())], 0, "CPIR", 16)
|
|
def cpir(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.HL = inc16(registers.HL)
|
|
registers.BC = dec16(registers.BC)
|
|
|
|
res = subtract8(registers.A, data[0], registers)
|
|
|
|
if registers.BC != 0 and res != 0:
|
|
registers.PC -= 2
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
registers.condition.PV = registers.BC != 0
|
|
return []
|
|
|
|
@instruction([(0xEDA9, ())], 0, "CPD", 16)
|
|
def cpd(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.HL = dec16(registers.HL)
|
|
registers.BC = dec16(registers.BC)
|
|
|
|
subtract8(registers.A, data[0], registers)
|
|
registers.condition.PV = registers.BC != 0
|
|
return []
|
|
|
|
@instruction([(0xEDB9, ())], 0, "CPDR", 16)
|
|
def cpdr(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.HL = dec16(registers.HL)
|
|
registers.BC = dec16(registers.BC)
|
|
|
|
res = subtract8(registers.A, data[0], registers)
|
|
|
|
if registers.BC != 0 and res != 0:
|
|
registers.PC -= 2
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
registers.condition.PV = registers.BC != 0
|
|
return []
|
|
|
|
#----------------------------------------------------------------------
|
|
# 8-Bit Arithmetic Group
|
|
#----------------------------------------------------------------------
|
|
#---- ADD ----
|
|
@instruction([(0x87, ("A",)), (0x80, ("B",)), (0x81, ("C",)),
|
|
(0x82, ("D",)), (0x83, ("E",)), (0x84, ("H",)),
|
|
(0x85, ("L",))], 0, "ADD A, {0}", 4)
|
|
def add_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = add8(registers.A, registers[r], registers)
|
|
return []
|
|
|
|
@instruction([([0xC6, '-'], ())], 1, "ADD A, {0:X}H", 7)
|
|
def add_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = add8(registers.A, n, registers)
|
|
return []
|
|
|
|
|
|
@instruction([(0x86, ())], 0, "ADD A, (HL)", 7)
|
|
def add_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.A = add8(registers.A, data[0], registers)
|
|
return []
|
|
|
|
@instruction([([0xDD, 0x86, '-'], ("IX",)),
|
|
([0xFD, 0x86, '-'], ("IY",))], 1, "ADD A, ({0}+{1:X}H)", 19)
|
|
def add_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
registers.A = add8(registers.A, data[0], registers)
|
|
return []
|
|
|
|
#---- ADC ----
|
|
@instruction([(0x8f, ("A",)), (0x88, ("B",)), (0x89, ("C",)),
|
|
(0x8A, ("D",)), (0x8B, ("E",)), (0x8C, ("H",)),
|
|
(0x8D, ("L",))], 0, "ADC A, {0}", 4)
|
|
def adc_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = add8(registers.A + registers.condition.C, registers[r], registers)
|
|
return []
|
|
|
|
@instruction([([0xCE, '-'], ())], 1, "ADC A, {0:X}H", 7)
|
|
def adc_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = add8(registers.A + registers.condition.C, n, registers)
|
|
return []
|
|
|
|
|
|
@instruction([(0x8E, ())], 0, "ADC A, (HL)", 7)
|
|
def adc_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.A = add8(registers.A + registers.condition.C, data[0], registers)
|
|
return []
|
|
|
|
@instruction([([0xDD, 0x8E, '-'], ("IX",)),
|
|
([0xFD, 0x8E, '-'], ("IY",))], 1, "ADC A, ({0}+{1:X}H)", 19)
|
|
def adc_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
registers.A = add8(registers.A + registers.condition.C, data[0], registers)
|
|
return []
|
|
|
|
#---- SUB ----
|
|
@instruction([(0x97, ("A",)), (0x90, ("B",)), (0x91, ("C",)),
|
|
(0x92, ("D",)), (0x93, ("E",)), (0x94, ("H",)),
|
|
(0x95, ("L",))], 0, "SUB A, {0}", 4)
|
|
def sub_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A, registers[r], registers)
|
|
return []
|
|
|
|
@instruction([([0xD6, '-'], ())], 1, "SUB A, {0:X}H", 7)
|
|
def sub_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A, n, registers)
|
|
return []
|
|
|
|
|
|
@instruction([(0x96, ())], 0, "SUB A, (HL)", 7)
|
|
def sub_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A, data[0], registers)
|
|
return []
|
|
|
|
@instruction([([0xDD, 0x96, '-'], ("IX",)),
|
|
([0xFD, 0x96, '-'], ("IY",))], 1, "SUB A, ({0}+{1:X}H)", 19)
|
|
def sub_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A, data[0], registers)
|
|
return []
|
|
|
|
#---- SBC ----
|
|
@instruction([(0x9f, ("A",)), (0x98, ("B",)), (0x99, ("C",)),
|
|
(0x9A, ("D",)), (0x9B, ("E",)), (0x9C, ("H",)),
|
|
(0x9D, ("L",))], 0, "SBC A, {0}", 4)
|
|
def sbc_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A - registers.condition.C, registers[r], registers)
|
|
return []
|
|
|
|
@instruction([([0xDE, '-'], ())], 1, "SBC A, {0:X}H", 7)
|
|
def sbc_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A - registers.condition.C, n, registers)
|
|
return []
|
|
|
|
|
|
@instruction([(0x9E, ())], 0, "SBC A, (HL)", 7)
|
|
def sbc_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A - registers.condition.C, data[0], registers)
|
|
return []
|
|
|
|
@instruction([([0xDD, 0x9E, '-'], ("IX",)),
|
|
([0xFD, 0x9E, '-'], ("IY",))], 1, "SBC A, ({0}+{1:X}H)", 19)
|
|
def sbc_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
registers.A = subtract8_check_overflow(registers.A - registers.condition.C, data[0], registers)
|
|
return []
|
|
|
|
#---- AND ----
|
|
@instruction([(0xa7, ("A",)), (0xa0, ("B",)), (0xa1, ("C",)),
|
|
(0xa2, ("D",)), (0xa3, ("E",)), (0xa4, ("H",)),
|
|
(0xa5, ("L",))], 0, "AND {0}", 4)
|
|
def and_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a_and_n(registers, registers[r])
|
|
registers.condition.S = (registers.A >> 7)
|
|
return []
|
|
|
|
@instruction([([0xe6, '-'], ())], 1, "AND {0:X}H", 7)
|
|
def and_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a_and_n(registers, n)
|
|
return []
|
|
|
|
|
|
@instruction([(0xa6, ())], 0, "AND (HL)", 7)
|
|
def and_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
a_and_n(registers, data[0])
|
|
return []
|
|
|
|
@instruction([([0xDD, 0xA6, '-'], ("IX",)),
|
|
([0xFD, 0xA6, '-'], ("IY",))], 1, "AND ({0}+{1:X}H)", 19)
|
|
def and_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
a_and_n(registers, data[0])
|
|
return []
|
|
|
|
#---- OR ----
|
|
@instruction([(0xb7, ("A",)), (0xb0, ("B",)), (0xb1, ("C",)),
|
|
(0xb2, ("D",)), (0xb3, ("E",)), (0xb4, ("H",)),
|
|
(0xb5, ("L",))], 0, "OR {0}", 4)
|
|
def or_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a_or_n(registers, registers[r])
|
|
registers.condition.S = (registers.A >> 7)
|
|
return []
|
|
|
|
@instruction([([0xf6, '-'], ())], 1, "OR {0:X}H", 7)
|
|
def or_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a_or_n(registers, n)
|
|
return []
|
|
|
|
|
|
@instruction([(0xb6, ())], 0, "OR (HL)", 7)
|
|
def or_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
a_or_n(registers, data[0])
|
|
return []
|
|
|
|
@instruction([([0xDD, 0xB6, '-'], ("IX",)),
|
|
([0xFD, 0xB6, '-'], ("IY",))], 1, "OR ({0}+{1:X}H)", 19)
|
|
def or_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
a_or_n(registers, data[0])
|
|
return []
|
|
|
|
#---- XOR ----
|
|
@instruction([(0xaf, ("A",)), (0xa8, ("B",)), (0xa9, ("C",)),
|
|
(0xaa, ("D",)), (0xab, ("E",)), (0xac, ("H",)),
|
|
(0xad, ("L",))], 0, "XOR {0}", 4)
|
|
def xor_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a_xor_n(registers, registers[r])
|
|
registers.condition.S = (registers.A >> 7)
|
|
return []
|
|
|
|
@instruction([([0xee, '-'], ())], 1, "XOR {0:X}H", 7)
|
|
def xor_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a_xor_n(registers, n)
|
|
return []
|
|
|
|
|
|
@instruction([(0xae, ())], 0, "XOR (HL)", 7)
|
|
def xor_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
a_xor_n(registers, data[0])
|
|
return []
|
|
|
|
@instruction([([0xDD, 0xAE, '-'], ("IX",)),
|
|
([0xFD, 0xAE, '-'], ("IY",))], 1, "XOR ({0}+{1:X}H)", 19)
|
|
def xor_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
a_xor_n(registers, data[0])
|
|
return []
|
|
|
|
#---- CP ----
|
|
@instruction([(0xbf, ("A",)), (0xb8, ("B",)), (0xb9, ("C",)),
|
|
(0xba, ("D",)), (0xbb, ("E",)), (0xbc, ("H",)),
|
|
(0xbd, ("L",))], 0, "CP {0}", 4)
|
|
def cp_a_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
subtract8_check_overflow(registers.A, registers[r], registers)
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([([0xfe, '-'], ())], 1, "CP {0:X}H", 7)
|
|
def cp_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
subtract8_check_overflow(registers.A, n, registers)
|
|
set_f5_f3(registers, n)
|
|
return []
|
|
|
|
|
|
@instruction([(0xbe, ())], 0, "CP (HL)", 7)
|
|
def cp_a_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
subtract8_check_overflow(registers.A, data[0], registers)
|
|
set_f5_f3(registers, data[0])
|
|
return []
|
|
|
|
@instruction([([0xDD, 0xBE, '-'], ("IX",)),
|
|
([0xFD, 0xBE, '-'], ("IY",))], 1, "CP ({0}+{1:X}H)", 19)
|
|
def cp_a_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
subtract8_check_overflow(registers.A, data[0], registers)
|
|
set_f5_f3(registers, data[0])
|
|
return []
|
|
|
|
#---- INC s ----
|
|
@instruction([(0x3c, ("A",)), (0x04, ("B",)), (0x0c, ("C",)),
|
|
(0x14, ("D",)), (0x1c, ("E",)), (0x24, ("H",)),
|
|
(0x2c, ("L",))], 0, "INC {0}", 4)
|
|
def inc_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = add8(registers[r], 1, registers, C=False )
|
|
return []
|
|
|
|
@instruction([(0x34, ())], 0, "INC (HL)", 11)
|
|
def inc_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
new = add8(data[0], 1, registers, C=False )
|
|
return [(registers.HL, new)]
|
|
|
|
@instruction([([0xDD, 0x34, '-'], ("IX",)),
|
|
([0xFD, 0x34, '-'], ("IY",))], 1, "INC ({0}+{1:X}H)", 23)
|
|
def inc_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
new = add8(data[0], 1, registers, C=False )
|
|
return [(registers.HL, new)]
|
|
|
|
|
|
#---- DEC s ----
|
|
@instruction([(0x3d, ("A",)), (0x05, ("B",)), (0x0d, ("C",)),
|
|
(0x15, ("D",)), (0x1d, ("E",)), (0x25, ("H",)),
|
|
(0x2d, ("L",))], 0, "DEC {0}", 4)
|
|
def dec_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.condition.PV = registers[r] == 0x80
|
|
registers[r] = subtract8(registers[r], 1, registers,
|
|
PV=False)
|
|
|
|
return []
|
|
|
|
@instruction([(0x35, ())], 0, "DEC (HL)", 11)
|
|
def dec_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
new = subtract8(data[0], 1, registers,
|
|
PV=False)
|
|
if data[0] == 0x80:
|
|
registers.condition.PV = 1
|
|
else:
|
|
registers.condition.PV = 0
|
|
|
|
return [(registers.HL, new)]
|
|
|
|
@instruction([([0xDD, 0x35, '-'], ("IX",)),
|
|
([0xFD, 0x35, '-'], ("IY",))], 1, "DEC ({0}+{1:X}H)", 23)
|
|
def dec_i_(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
new = subtract8(data[0], 1, registers,
|
|
PV=False)
|
|
if data[0] == 0x80:
|
|
registers.condition.PV = 1
|
|
else:
|
|
registers.condition.PV = 0
|
|
return [(registers[i] + get_8bit_twos_comp(d), new)]
|
|
|
|
#--------------------------------------------------------------------
|
|
# General-Purpose Arithmetic and CPU Control Groups
|
|
#--------------------------------------------------------------------
|
|
@instruction([(0x27, ())], 0, "DAA", 4)
|
|
def daa(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if registers.condition.N == 0:
|
|
# add operation
|
|
if registers.condition.C == 0:
|
|
pass
|
|
else:
|
|
pass
|
|
pass
|
|
else:
|
|
pass
|
|
# TODO: implement DAA
|
|
#raise Exception("DAA Not implemented ")
|
|
return []
|
|
|
|
@instruction([(0x2F, ())], 0, "CPL", 4)
|
|
def cpl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = 0xFF ^ registers.A
|
|
registers.condition.N = 1
|
|
registers.condition.H = 1
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
|
|
@instruction([(0xED44, ())], 0, "NEG", 8)
|
|
def neg(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.A = subtract8_check_overflow(0, registers.A, registers)
|
|
return []
|
|
|
|
@instruction([(0x3F, ())], 0, "CCF", 4)
|
|
def ccf(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.condition.H = registers.condition.C
|
|
registers.condition.N = 0
|
|
registers.condition.C = not registers.condition.C
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
@instruction([(0x37, ())], 0, "SCF", 4)
|
|
def scf(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
registers.condition.C = 1
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
@instruction([(0x00, ())], 0, "NOP", 4)
|
|
def nop(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
return []
|
|
|
|
@instruction([(0x76, ())], 0, "HALT", 4)
|
|
def halt(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.HALT = True
|
|
registers.PC -= 1
|
|
return []
|
|
|
|
|
|
@instruction([(0xF3, ())], 0, "DI", 4)
|
|
def di(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.IFF = False
|
|
registers.IFF2 = False
|
|
return []
|
|
|
|
@instruction([(0xFB, ())], 0, "EI", 4)
|
|
def ei(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.IFF = True
|
|
registers.IFF2 = True
|
|
return []
|
|
|
|
@instruction([(0xED46, (0,)), (0xED56, (1,)), (0xED5E, (2,))], 0, "IM {}", 8)
|
|
def im(instruction, registers, get_reads, data, mode):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.IM = mode
|
|
return []
|
|
|
|
|
|
#--------------------------------------------------------------------
|
|
# 16-Bit Arithmetic Group
|
|
#--------------------------------------------------------------------
|
|
@instruction([(0x39, ("SP",)), (0x09, ("BC",)), (0x19, ("DE",)),(0x29, ("HL",))], 0, "ADD HL, {0}", 11)
|
|
def add16_hl(instruction, registers, get_reads, data, reg):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
val = registers.HL + getattr(registers, reg)
|
|
dummy_reg = registers.create()
|
|
add8(registers.HL & 0xFF, getattr(registers, reg) & 0xFF, dummy_reg, PV=True)
|
|
registers.condition.H = dummy_reg.condition.C
|
|
add8(registers.HL >> 8, getattr(registers, reg) >> 8, dummy_reg, PV=True)
|
|
registers.condition.F3 = dummy_reg.condition.F3
|
|
registers.condition.F5 = dummy_reg.condition.F5
|
|
registers.condition.N = 0
|
|
registers.condition.C = val > 0xFFFF
|
|
registers.HL = val & 0xFFFF
|
|
return []
|
|
|
|
@instruction([(0xED7A, ("SP",)), (0xED4A, ("BC",)), (0xED5A, ("DE",)),(0xED6A, ("HL",))], 0, "ADC HL, {0}", 15)
|
|
def adc16_hl(instruction, registers, get_reads, data, reg):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.HL = add16(registers.HL + registers.condition.C, getattr(registers, reg), registers)
|
|
|
|
return []
|
|
|
|
@instruction([(0xED72, ("SP",)), (0xED42, ("BC",)), (0xED52, ("DE",)),(0xED62, ("HL",))], 0, "SBC HL, {0}", 15)
|
|
def sbc16_hl(instruction, registers, get_reads, data, reg):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
a = registers.HL
|
|
b = registers[reg]
|
|
res = a - b
|
|
if registers.condition.C:
|
|
res -= 1
|
|
registers.condition.S = (res >> 15) & 0x01
|
|
registers.condition.N = 1
|
|
registers.condition.Z = (res == 0)
|
|
registers.condition.F3 = res & 0x0800
|
|
registers.condition.F5 = res & 0x2000
|
|
if (b & 0xFFF) > (a & 0xFFF) - registers.condition.C :
|
|
registers.condition.H = 1
|
|
else:
|
|
registers.condition.H = 0
|
|
|
|
pvtest = get_16bit_twos_comp(a) - get_16bit_twos_comp(b) - registers.condition.C
|
|
if pvtest < -32768 or pvtest > 32767:
|
|
registers.condition.PV = 1 # overflow
|
|
else:
|
|
registers.condition.PV = 0
|
|
|
|
registers.condition.C = res > 0xFFFF or res < 0
|
|
registers.HL = res & 0xFFFF
|
|
|
|
return []
|
|
|
|
@instruction([(0xDD39, ("IX", "SP",)), (0xDD09, ("IX", "BC",)), (0xDD19, ("IX", "DE",)),(0xDD29, ("IX", "IX",)),
|
|
(0xFD39, ("IY", "SP",)), (0xFD09, ("IY", "BC",)), (0xFD19, ("IY", "DE",)),(0xFD29, ("IY", "IY",))],
|
|
0, "ADD {0}, {1}", 15)
|
|
def add16_i_pp(instruction, registers, get_reads, data, i, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
val = registers[i] + registers[r]
|
|
if ((registers[i] & 0xFFF) + (registers[r] & 0xFFF)) > 0xFFF :
|
|
registers.condition.H = 1
|
|
else:
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
registers.condition.C = val > 0xFFFF
|
|
set_f5_f3(registers, (registers[i] >>8)+(registers[r]>>8))
|
|
registers[i] = val & 0xFFFF
|
|
return []
|
|
|
|
|
|
@instruction([(0x33, ("SP",)), (0x03, ("BC",)), (0x13, ("DE",)),(0x23, ("HL",)),
|
|
(0xDD23, ("IX",), 10), (0xFD23, ("IY",), 10)],
|
|
0, "INC {0}", 6)
|
|
def inc16_ss(instruction, registers, get_reads, data, s):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[s] = inc16(registers[s])
|
|
return []
|
|
|
|
|
|
@instruction([(0x3b, ("SP",)), (0x0b, ("BC",)), (0x1b, ("DE",)),(0x2b, ("HL",)),
|
|
(0xDD2b, ("IX",), 10), (0xFD2b, ("IY",), 10)],
|
|
0, "DEC {0}", 6)
|
|
def dec16_ss(instruction, registers, get_reads, data, s):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[s] = dec16(registers[s])
|
|
return []
|
|
|
|
#--------------------------------------------------------------------
|
|
# Rotate and Shift Group
|
|
#--------------------------------------------------------------------
|
|
@instruction([(0x07, ())], 0, "RLCA", 4)
|
|
def rlca(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
c = registers.A >> 7
|
|
registers.A = ((registers.A << 1) | c) & 0xFF
|
|
registers.condition.C = c
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
@instruction([(0x17, ())], 0, "RLA", 4)
|
|
def rla(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
c = registers.A >> 7
|
|
pc = registers.condition.C
|
|
registers.A = (registers.A << 1 | pc) & 0xFF
|
|
registers.condition.C = c
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
@instruction([(0x0F, ())], 0, "RRCA", 4)
|
|
def rrca(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
c = registers.A & 0x01
|
|
registers.A = (registers.A >> 1 | c << 7) & 0xFF
|
|
registers.condition.C = c
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
@instruction([(0x1F, ())], 0, "RRA", 4)
|
|
def rra(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
c = registers.A & 0x01
|
|
pc = registers.condition.C
|
|
registers.A = (registers.A >> 1 | pc << 7) & 0xFF
|
|
registers.condition.C = c
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
set_f5_f3_from_a(registers)
|
|
return []
|
|
|
|
|
|
# RLC m
|
|
@instruction([(0xCB07, ("A", )), (0xCB00, ("B", )), (0xCB01, ("C", )), (0xCB02, ("D", )),
|
|
(0xCB03, ("E", )), (0xCB04, ("H", )), (0xCB05, ("L", ))],
|
|
0, "RLC {0}", 8)
|
|
def rlc(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = rotate_left_carry(registers, registers[r])
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([(0xCB06, ( ))],
|
|
0, "RLC (HL)", 15)
|
|
def rlc_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = rotate_left_carry(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers.HL, val)]
|
|
|
|
|
|
@instruction([([0xDD, 0xCB, '-', 0x06], ("IX", )),
|
|
([0xFD, 0xCB, '-', 0x06], ("IY", ))],
|
|
2, "RLC ({0}+{1:X}H)", 23)
|
|
def rlc_i_d(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
new = rotate_left_carry(registers, data[0])
|
|
set_f5_f3(registers, new)
|
|
return [(registers[i] + get_8bit_twos_comp(d), new)]
|
|
|
|
# RL m
|
|
@instruction([([0xCB, 0x10], ("B", )), ([0xCB, 0x11], ("C", )), ([0xCB, 0x12], ("D", )),
|
|
([0xCB, 0x13], ("E", )), ([0xCB, 0x14], ("H", )), ([0xCB, 0x15], ("L", )),
|
|
([0xCB, 0x17], ("A", ))],
|
|
2, "RL {0}", 8)
|
|
def rl_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = rotate_left(registers, registers[r])
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([([0xCB, 0x16], ())],
|
|
2, "RL (HL)", 15)
|
|
def rl_hl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = rotate_left(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers.HL, val)]
|
|
|
|
@instruction([([0xDD, 0xCB, "-", 0x16], ("IX", )),
|
|
([0xFD, 0xCB, "-", 0x16], ("IY", ))],
|
|
2, "RL ({0}+{1:X}H)", 23)
|
|
def rl_i(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
val = rotate_left(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers[i] + get_8bit_twos_comp(d), val)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# RRC m
|
|
@instruction([(0xCB0F, ("A", )), (0xCB08, ("B", )), (0xCB09, ("C", )), (0xCB0A, ("D", )),
|
|
(0xCB0B, ("E", )), (0xCB0C, ("H", )), (0xCB0D, ("L", ))],
|
|
0, "RRC {0}", 8)
|
|
def rrc(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = rotate_right_carry(registers, registers[r])
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([(0xCB0E, ( ))],
|
|
0, "RRC (HL)", 15)
|
|
def rrc_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = rotate_right_carry(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers.HL, val)]
|
|
|
|
|
|
@instruction([([0xDD, 0xCB, '-', 0x0E], ("IX", )),
|
|
([0xFD, 0xCB, '-', 0x0E], ("IY", ))],
|
|
2, "RRC ({0}+{1:X}H)", 23)
|
|
def rrc_i_d(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
new = rotate_right_carry(registers, data[0])
|
|
set_f5_f3(registers, new)
|
|
return [(registers[i] + get_8bit_twos_comp(d), new)]
|
|
|
|
# RR m
|
|
@instruction([([0xCB, 0x18], ("B", )), ([0xCB, 0x19], ("C", )), ([0xCB, 0x1A], ("D", )),
|
|
([0xCB, 0x1B], ("E", )), ([0xCB, 0x1C], ("H", )), ([0xCB, 0x1D], ("L", )),
|
|
([0xCB, 0x1F], ("A", ))],
|
|
2, "RR {0}", 8)
|
|
def rr_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = rotate_right(registers, registers[r])
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([([0xCB, 0x1E], ())],
|
|
2, "RR (HL)", 15)
|
|
def rr_hl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = rotate_right(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers.HL, val)]
|
|
|
|
@instruction([([0xDD, 0xCB, "-", 0x1E], ("IX", )),
|
|
([0xFD, 0xCB, "-", 0x1E], ("IY", ))],
|
|
2, "RR ({0}+{1:X}H)", 23)
|
|
def rr_i(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
val = rotate_right(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers[i] + get_8bit_twos_comp(d), val)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# SLA m
|
|
@instruction([(0xCB27, ("A", )), (0xCB20, ("B", )), (0xCB21, ("C", )), (0xCB22, ("D", )),
|
|
(0xCB23, ("E", )), (0xCB24, ("H", )), (0xCB25, ("L", ))],
|
|
0, "SLA {0}", 8)
|
|
def sla_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = shift_left(registers, registers[r])
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([(0xCB26, ( ))],
|
|
0, "SLA (HL)", 15)
|
|
def sla_hl_(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = shift_left(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers.HL, val)]
|
|
|
|
|
|
@instruction([([0xDD, 0xCB, '-', 0x26], ("IX", )),
|
|
([0xFD, 0xCB, '-', 0x26], ("IY", ))],
|
|
2, "SLA ({0}+{1:X}H)", 23)
|
|
def sla_i_d(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
new = shift_left(registers, data[0])
|
|
set_f5_f3(registers, new)
|
|
return [(registers[i] + get_8bit_twos_comp(d), new)]
|
|
|
|
|
|
# SRA m
|
|
@instruction([([0xCB, 0x28], ("B", )), ([0xCB, 0x29], ("C", )), ([0xCB, 0x2A], ("D", )),
|
|
([0xCB, 0x2B], ("E", )), ([0xCB, 0x2C], ("H", )), ([0xCB, 0x2D], ("L", )),
|
|
([0xCB, 0x2F], ("A", ))],
|
|
2, "SRA {0}", 8)
|
|
def sra_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[r] = shift_right(registers, registers[r])
|
|
set_f5_f3(registers, registers[r])
|
|
return []
|
|
|
|
@instruction([([0xCB, 0x2E], ())],
|
|
2, "SRA (HL)", 15)
|
|
def sra_hl(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = shift_right(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers.HL, val)]
|
|
|
|
@instruction([([0xDD, 0xCB, "-", 0x2E], ("IX", )),
|
|
([0xFD, 0xCB, "-", 0x2E], ("IY", ))],
|
|
2, "SRA ({0}+{1:X}H)", 23)
|
|
def sra_i(instruction, registers, get_reads, data, i, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
val = shift_right(registers, data[0])
|
|
set_f5_f3(registers, val)
|
|
return [(registers[i] + get_8bit_twos_comp(d), val)]
|
|
|
|
@instruction([([0xED, 0x6F], ())],
|
|
2, "RLD", 18)
|
|
def rld(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
a = (data[0] >> 4) | (registers.A & 0xF0)
|
|
hl = ((registers.HL << 4) | (registers.A & 0x0f)) & 0xFF
|
|
registers.A = a
|
|
registers.condition.S = a >> 7
|
|
registers.condition.Z = a == 0
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
registers.condition.PV = parity(a)
|
|
set_f5_f3(registers, registers.A)
|
|
return [(registers.HL, hl)]
|
|
|
|
@instruction([([0xED, 0x67], ())],
|
|
2, "RRD", 18)
|
|
def rrd(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
a = (data[0] & 0x0F) | (registers.A & 0xF0)
|
|
hl = ((registers.HL >> 4) | (registers.A << 4)) & 0xFF
|
|
registers.A = a
|
|
registers.condition.S = a >> 7
|
|
registers.condition.Z = a == 0
|
|
registers.condition.H = 0
|
|
registers.condition.N = 0
|
|
registers.condition.PV = parity(a)
|
|
set_f5_f3(registers, registers.A)
|
|
return [(registers.HL, hl)]
|
|
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------
|
|
# Bit Set, Reset, and Test Group
|
|
#--------------------------------------------------------------------
|
|
@instruction([ ([0xCB, 0x40 + (b << 3) + register_bits[reg]], (b, reg))
|
|
for b in range(8)
|
|
for reg in ['A', 'B', 'C', 'D', 'E', 'H', 'L'] ] ,
|
|
2, "BIT {0}, {1}", 8)
|
|
def bit_r(instruction, registers, get_reads, data, bit, reg):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
# print "Test bit ", bit
|
|
registers.condition.Z = (registers[reg] & (0x01 << bit)) == 0
|
|
registers.condition.H = 1
|
|
registers.condition.N = 0
|
|
registers.condition.PV = registers.condition.Z
|
|
if bit == 7:
|
|
registers.condition.S = (registers[reg] & (0x01 << bit))
|
|
#if bit == 5:
|
|
#registers.condition.F5 = (registers[reg] & (0x01 << bit))
|
|
#if bit == 3:
|
|
#registers.condition.F3 = (registers[reg] & (0x01 << bit))
|
|
set_f5_f3(registers, registers[reg])
|
|
return []
|
|
|
|
@instruction( [ ([0xCB, 0x40 + (b << 3) + 6], (b,)) for b in range(8) ] ,
|
|
2, "BIT {0}, (HL)", 12)
|
|
def bit_hl(instruction, registers, get_reads, data, bit):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
registers.condition.Z = (data[0] & (0x01 << bit)) == 0
|
|
registers.condition.H = 1
|
|
registers.condition.N = 0
|
|
registers.condition.PV = registers.condition.Z
|
|
if bit == 7:
|
|
registers.condition.S = (data[0] & (0x01 << bit))
|
|
set_f5_f3(registers, data[0])
|
|
return []
|
|
|
|
@instruction( [ ([I, 0xCB, '-', 0x40 + (b << 3) + 6], (Ir, b,)) for b in range(8) for I, Ir in index_bytes] ,
|
|
2, "BIT {1}, ({0}+{2:X}H)", 20)
|
|
def bit_i(instruction, registers, get_reads, data, i, bit, d):
|
|
if get_reads:
|
|
return [registers[i]+get_8bit_twos_comp(d)]
|
|
else:
|
|
registers.condition.Z = (data[0] & (0x01 << bit)) == 0
|
|
registers.condition.H = 1
|
|
registers.condition.N = 0
|
|
registers.condition.PV = registers.condition.Z
|
|
if bit == 7:
|
|
registers.condition.S = (data[0] & (0x01 << bit))
|
|
else:
|
|
registers.condition.S = 0
|
|
set_f5_f3(registers, (registers[i]+get_8bit_twos_comp(d)) >> 8)
|
|
return []
|
|
|
|
@instruction([ ([0xCB, 0xc0 + (b << 3) + register_bits[reg]], (b, reg))
|
|
for b in range(8)
|
|
for reg in ['A', 'B', 'C', 'D', 'E', 'H', 'L'] ] ,
|
|
2, "SET {0}, {1}", 8)
|
|
def set_r(instruction, registers, get_reads, data, bit, reg):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[reg] |= (0x01 << bit)
|
|
return []
|
|
|
|
@instruction( [ ([0xCB, 0xc0 + (b << 3) + 6], (b,)) for b in range(8) ] ,
|
|
2, "SET {0}, (HL)", 15)
|
|
def set_hl(instruction, registers, get_reads, data, bit):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = data[0] | (0x01 << bit)
|
|
return [(registers.HL, val)]
|
|
|
|
@instruction( [ ([I, 0xCB, '-', 0xc0 + (b << 3) + 6], (Ir, b,))
|
|
for b in range(8)
|
|
for I, Ir in index_bytes] ,
|
|
2, "SET {1}, ({0}+{2:X}H)", 23)
|
|
def set_i(instruction, registers, get_reads, data, i, bit, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
val = data[0] | (0x01 << bit)
|
|
return [(registers[i] + get_8bit_twos_comp(d), val)]
|
|
|
|
@instruction([ ([0xCB, 0x80 + (b << 3) + register_bits[reg]], (b, reg))
|
|
for b in range(8)
|
|
for reg in ['A', 'B', 'C', 'D', 'E', 'H', 'L'] ] ,
|
|
2, "RES {0}, {1}", 8)
|
|
def res_r(instruction, registers, get_reads, data, bit, reg):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers[reg] &= ~(0x01 << bit)
|
|
return []
|
|
|
|
@instruction( [ ([0xCB, 0x80 + (b << 3) + 6], (b,))
|
|
for b in range(8) ] ,
|
|
2, "RES {0}, (HL)", 15)
|
|
def res_hl(instruction, registers, get_reads, data, bit):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
val = data[0] & ~(0x01 << bit)
|
|
return [(registers.HL, val)]
|
|
|
|
@instruction( [ ([I, 0xCB, '-', 0x80 + (b << 3) + 6], (Ir, b,))
|
|
for b in range(8)
|
|
for I, Ir in index_bytes] ,
|
|
2, "RES {1}, ({0}+{2:X}H)", 23)
|
|
def res_i(instruction, registers, get_reads, data, i, bit, d):
|
|
if get_reads:
|
|
return [registers[i] + get_8bit_twos_comp(d)]
|
|
else:
|
|
val = data[0] & ~(0x01 << bit)
|
|
return [(registers[i] + get_8bit_twos_comp(d), val)]
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------
|
|
# Jump Group
|
|
#--------------------------------------------------------------------
|
|
@instruction([([0xC3, '-', '-'], ())],
|
|
2, "JP {1:X}{0:X}H", 10)
|
|
def jp(instruction, registers, get_reads, data, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.PC = n2 << 8 | n
|
|
return []
|
|
|
|
|
|
@instruction([([0xC2+offset, '-', '-'], (reg, reg_name, val))
|
|
for offset, reg_name, reg, val in conditions],
|
|
2, "JP {1}, {4:x}{3:X}H", 10)
|
|
def jp_c(instruction, registers, get_reads, data, reg, reg_name, val, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if getattr(registers.condition, reg) == val:
|
|
registers.PC = n2 << 8 | n
|
|
return []
|
|
|
|
|
|
|
|
@instruction([([0x18, '-'], ())],
|
|
2, "JR {0:X}H", 12)
|
|
def jr(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
offset_pc(registers, n)
|
|
return []
|
|
|
|
@instruction([([0x20, '-'], ())],
|
|
2, "JR NZ, {0:X}H", 12)
|
|
def jr_nz(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if not registers.condition.Z:
|
|
offset_pc(registers, n)
|
|
instruction.tstates = 12
|
|
else:
|
|
instruction.tstates = 7
|
|
return []
|
|
|
|
|
|
@instruction([([0x28, '-'], ())],
|
|
2, "JR Z, {0:X}H", 12)
|
|
def jr_z(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if registers.condition.Z:
|
|
offset_pc(registers, n)
|
|
instruction.tstates = 12
|
|
else:
|
|
instruction.tstates = 7
|
|
return []
|
|
|
|
|
|
@instruction([([0x30, '-'], ())],
|
|
2, "JR NC, {0:X}H", 12)
|
|
def jr_nc(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if not registers.condition.C:
|
|
offset_pc(registers, n)
|
|
instruction.tstates = 12
|
|
else:
|
|
instruction.tstates = 7
|
|
return []
|
|
|
|
|
|
@instruction([([0x38, '-'], ())],
|
|
2, "JR C, {0:X}H", 12)
|
|
def jr_c(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if registers.condition.C:
|
|
offset_pc(registers, n)
|
|
instruction.tstates = 12
|
|
else:
|
|
instruction.tstates = 7
|
|
return []
|
|
|
|
@instruction([([0xE9], ("HL", )),([0xDD, 0xE9], ("IX", ), 8),([0xFD, 0xE9], ("IY", ), 8) ],
|
|
2, "JP ({})", 4)
|
|
def jp_r(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.PC = registers[r]
|
|
return []
|
|
|
|
@instruction([([0x10, '-'], ())],
|
|
2, "DJNZ {0:X}H", 13)
|
|
def djnz(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
registers.B = dec8(registers.B)
|
|
if not registers.B == 0:
|
|
offset_pc(registers, n)
|
|
instruction.tstates = 13
|
|
else:
|
|
instruction.tstates = 8
|
|
return []
|
|
|
|
#--------------------------------------------------------------------
|
|
# Call And Return Group
|
|
#--------------------------------------------------------------------
|
|
@instruction([([0xCD, '-', '-'], ())],
|
|
2, "CALL {1:X}{0:X}H", 17)
|
|
def call(instruction, registers, get_reads, data, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
sp = registers.SP
|
|
pc = registers.PC
|
|
registers.SP = dec16(registers.SP)
|
|
registers.SP = dec16(registers.SP)
|
|
registers.PC = n2 << 8 | n
|
|
return [(sp - 1, pc >> 8),
|
|
(sp - 2, pc & 0xFF)]
|
|
|
|
@instruction([([0xC4+offset, '-', '-'], (reg, reg_name, val))
|
|
for offset, reg_name, reg, val in conditions],
|
|
2, "CALL {1}, {4:x}{3:X}H", 17)
|
|
def call_c(instruction, registers, get_reads, data, reg, reg_name, val, n, n2):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if getattr(registers.condition, reg) == val:
|
|
instruction.tstates = 17
|
|
sp = registers.SP
|
|
pc = registers.PC
|
|
registers.SP = dec16(registers.SP)
|
|
registers.SP = dec16(registers.SP)
|
|
registers.PC = n2 << 8 | n
|
|
return [(sp - 1, pc >> 8),
|
|
(sp - 2, pc & 0xFF)]
|
|
else:
|
|
instruction.tstates = 10
|
|
return []
|
|
|
|
@instruction([([0xC9], ())],
|
|
2, "RET", 10)
|
|
def ret(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.SP, inc16(registers.SP)]
|
|
else:
|
|
registers.SP = inc16(registers.SP)
|
|
registers.SP = inc16(registers.SP)
|
|
registers.PC = data[1] << 8 | data[0]
|
|
return []
|
|
|
|
@instruction([([0xC0+offset], (reg, reg_name, val))
|
|
for offset, reg_name, reg, val in conditions],
|
|
2, "RET {1}", 11)
|
|
def ret_c(instruction, registers, get_reads, data, reg, reg_name, val):
|
|
if get_reads:
|
|
return [registers.SP, inc16(registers.SP)]
|
|
else:
|
|
if getattr(registers.condition, reg) == val:
|
|
registers.SP = inc16(registers.SP)
|
|
registers.SP = inc16(registers.SP)
|
|
registers.PC = data[1] << 8 | data[0]
|
|
instruction.tstates = 11
|
|
else:
|
|
instruction.tstates = 5
|
|
return []
|
|
|
|
@instruction([([0xed, 0x4d], ())], 2, "RETI", 14)
|
|
def reti(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.SP, inc16(registers.SP)]
|
|
else:
|
|
#TODO: implement return from interrupt
|
|
logging.warn("RETI not fully implemented")
|
|
registers.SP = inc16(registers.SP)
|
|
registers.SP = inc16(registers.SP)
|
|
registers.PC = data[1] << 8 | data[0]
|
|
return []
|
|
|
|
@instruction([([0xed, 0x45], ())], 2, "RETN", 14)
|
|
def retn(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.SP, inc16(registers.SP)]
|
|
else:
|
|
#TODO: implement from non masked interrupt
|
|
logging.warn("RETN not fully implemented")
|
|
registers.SP = inc16(registers.SP)
|
|
registers.SP = inc16(registers.SP)
|
|
registers.PC = data[1] << 8 | data[0]
|
|
registers.IFF = registers.IFF2
|
|
return []
|
|
|
|
@instruction([([0xC7 + (t << 3) ], (p, )) for t, p in enumerate([0x0, 0x08, 0x10, 0x18,
|
|
0x20, 0x28, 0x30, 0x38]) ] ,
|
|
2, "RST {0:X}H", 11)
|
|
def rst_p(instruction, registers, get_reads, data, p):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
sp = registers.SP
|
|
pc = registers.PC
|
|
registers.SP = dec16(registers.SP)
|
|
registers.SP = dec16(registers.SP)
|
|
registers.PC = p
|
|
return [(sp - 1, pc >> 8),
|
|
(sp - 2, pc & 0xFF)]
|
|
|
|
#--------------------------------------------------------------------
|
|
# Input Output Group
|
|
#--------------------------------------------------------------------
|
|
@instruction([([0xDB, '-'], ( )) ] ,
|
|
2, "IN A, ({0:X}H)", 11)
|
|
def in_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
address = n | (registers.A << 8) # registers.C | (registers.B << 8)
|
|
return [address+0x10000]
|
|
else:
|
|
registers.A = data[0]
|
|
return []
|
|
|
|
@instruction([([0xEd, 0x40+(i<<3)], (r, )) for i, r in enumerate("BCDEHLFA")] ,
|
|
2, "IN {0}, (C)", 12)
|
|
def in_r_c(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
address = registers[r] | (registers.B << 8) #n | (registers.A << 8)
|
|
return [address+0x10000]
|
|
else:
|
|
registers.condition.S = data[0] & 0x80
|
|
registers.condition.Z = data[0] == 0
|
|
registers.condition.H = 0
|
|
registers.condition.PV = parity(data[0])
|
|
registers.condition.N = 0
|
|
if r == "F":
|
|
return []
|
|
#registers[r] = data[0]
|
|
return []
|
|
|
|
@instruction([([0xed, 0xa2], ( )) ] ,
|
|
2, "INI", 16)
|
|
def ini(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
address = registers.C | (registers.B << 8)
|
|
return [address+0x10000]
|
|
else:
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = inc16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
return [(dec16(registers.HL), data[0])]
|
|
|
|
|
|
@instruction([([0xed, 0xb2], ( )) ] ,
|
|
2, "INIR", 21)
|
|
def inir(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
address = registers.C | (registers.B << 8)
|
|
return [address+0x10000]
|
|
else:
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = inc16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
if registers.B == 0:
|
|
dec16(registers.PC)
|
|
dec16(registers.PC)
|
|
instruction.tstates = 16
|
|
else:
|
|
instruction.tstates = 21
|
|
return [(dec16(registers.HL), data[0])]
|
|
|
|
@instruction([([0xed, 0xaa], ( )) ] ,
|
|
2, "IND", 16)
|
|
def ind(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
address = registers.C | (registers.B << 8)
|
|
return [address+0x10000]
|
|
else:
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = dec16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
return [(dec16(registers.HL), data[0])]
|
|
|
|
|
|
@instruction([([0xed, 0xba], ( )) ] ,
|
|
2, "INDR", 21)
|
|
def indr(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
address = registers.C | (registers.B << 8)
|
|
return [address+0x10000]
|
|
else:
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = dec16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
if not registers.B == 0:
|
|
dec16(registers.PC)
|
|
dec16(registers.PC)
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
return [(dec16(registers.HL), data[0])]
|
|
|
|
@instruction([([0xD3, '-'], ( )) ] ,
|
|
2, "OUT ({0:X}H), A", 11)
|
|
def out_a_n(instruction, registers, get_reads, data, n):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
address = n | (registers.A << 8)
|
|
#if n == 0x81:
|
|
##logging.info("=========================================== %s =="%chr(registers.A))
|
|
##print chr(registers.A),
|
|
#sys.stdout.flush()
|
|
return [(address+0x10000, registers.A)]
|
|
|
|
@instruction([([0xEd, 0x41+(i<<3)], (r, )) for i, r in enumerate("BCDEHLFA")] ,
|
|
2, "OUT (C), {0}", 12)
|
|
def out_r_c(instruction, registers, get_reads, data, r):
|
|
if get_reads:
|
|
return []
|
|
else:
|
|
if r == "F":
|
|
return []
|
|
return [(registers.BC+0x10000, registers[r])]
|
|
|
|
@instruction([([0xed, 0xa3], ( )) ] ,
|
|
2, "OUTI", 16)
|
|
def outi(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
address = registers.C | (registers.B << 8)
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = inc16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
return [(address+0x10000, data[0])]
|
|
|
|
|
|
@instruction([([0xed, 0xb3], ( )) ] ,
|
|
2, "OTIR", 21)
|
|
def otir(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
address = registers.C | (registers.B << 8)
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = inc16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
if not registers.B == 0:
|
|
dec16(registers.PC)
|
|
dec16(registers.PC)
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
|
|
return [(registers.BC+0x10000, data[0])]
|
|
|
|
@instruction([([0xed, 0xab], ( )) ] ,
|
|
2, "OUTD", 16)
|
|
def outd(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
address = registers.C | (registers.B << 8)
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = dec16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
return [(registers.BC+0x10000, data[0])]
|
|
|
|
|
|
@instruction([([0xed, 0xbb], ( )) ] ,
|
|
2, "OTDR", 21)
|
|
def otdr(instruction, registers, get_reads, data):
|
|
if get_reads:
|
|
return [registers.HL]
|
|
else:
|
|
address = registers.C | (registers.B << 8)
|
|
registers.B = dec8(registers.B)
|
|
registers.HL = dec16(registers.HL)
|
|
registers.condition.N = 1
|
|
registers.condition.Z = registers.B == 0
|
|
if not registers.B == 0:
|
|
dec16(registers.PC)
|
|
dec16(registers.PC)
|
|
instruction.tstates = 21
|
|
else:
|
|
instruction.tstates = 16
|
|
|
|
return [(registers.BC+0x10000, data[0])]
|