Skip to content

Instantly share code, notes, and snippets.

@kamawanu
Last active February 9, 2022 00:23
Show Gist options
  • Save kamawanu/465b81d7483504943be03da4668b77d3 to your computer and use it in GitHub Desktop.
Save kamawanu/465b81d7483504943be03da4668b77d3 to your computer and use it in GitHub Desktop.
z80 instruction set implements by python3, experimental, planning,
from z80 import z80, _decode_0
import reg
import inspect
from typing import Optional
def unref(data) -> Optional[str]:
return z80.what(data)
def bin_n(data, to2) -> str:
fmt = "0b{0:0%db}" % to2
return str.format(fmt, data)
def undump_any(data, to2: int = -1) -> str:
# print("#", data)
if type(data) == int:
# fmt = "0b{0:0%db}" % to2
return bin_n(data, to2) if to2 > 0 else str(data)
elif type(data) == str:
try:
z80().__getattribute__(data)
return "instr." + data
except:
pass
return "\"" + data + "\""
elif type(data) == property:
return unref(data)
elif type(data) == list:
# print("#@", data)
return undump_l(data, to2)
elif type(data) == dict:
# print("#%", data)
v = unref(data)
if v != None:
return v
pz = []
for kk, vv in data.items():
pz.append(bin_n(kk, to2) + ":" + undump_any(vv, to2))
return "{"+(",".join(pz))+"}"
elif callable(data):
# print("#??", data)
return unref(data)
else:
return "\"" + str(data) + "\""
def undump_l(data: list, to2: int) -> str:
tk = []
# to2 = True
subs = [to2, ] * len(data)
if len(data) >= 2 and type(data[1]) == list:
subs = data[1][:]
subs.insert(1, -1)
# print(subs)
for vv, to2 in zip(data, subs):
tk.append(undump_any(vv, to2))
return "[" + (",".join(tk)) + "]"
def undump_l0(data: list) -> str:
tk = []
to2 = 8
for vv in data:
tk.append(undump_any(vv, to2))
to2 = -1
return "[" + (",".join(tk)) + "]"
bmap = None
for op1x in _decode_0:
if type(op1x) == list:
whos = [type(x) for x in op1x]
if whos == [int, int, int] or whos == [int, int]:
# print(whos)
bmap = op1x
continue
if op1x == None:
continue
if type(op1x) == int:
op1x = [op1x, ""]
# print(op1x)
# op1x = op1x[:-1]
# op1x[-1] = op1x[-1]
# def rxx():
if type(op1x[-1]) != list:
op1x[-1] = [op1x[-1], ]
# print("#", oper, tkns)
argn = 1
for ii in range(1, min(3, len(op1x))):
# print(ii)
# print("#?", op1x[ii])
if type(op1x[ii]) == dict:
if len(op1x[-1]) <= ii:
op1x[-1].append(argn)
if len(op1x[ii]) == 1:
kka = list(op1x[ii].keys())
# print("#???", kka)
kk = kka[0]
op1x[-1][ii] = op1x[ii][kk]
op1x[ii] = kk
# print(op1x[-1])
argn += 1
if len(op1x) > 2:
op1x = [
[
op1x[0],
bmap
]+op1x[1:-1],
op1x[-1],
]
if type(op1x[0]) == int:
op1x[0] = [op1x[0], [8, ]]
# op1x = op1x + [op1x[-1], ]
# print(oper)
outstr = undump_l0(op1x)
print(outstr, ",")
import z80
for datum in z80._decode_0:
if datum == None:
continue
print(z80.expand_1b(datum), datum)
class stubs(object):
def ADD(self, reg: property, opr: property):
pass
def ADC(self, dst: property, src: property):
pass
def SUB(self, dst: property, src: property):
pass
def SBC(self, dst: property, src: property):
pass
def AND(self, dst: property, src: property):
pass
def XOR(self, dst: property, src: property):
pass
def OR(self, dst: property, src: property):
pass
def PUSH(self, dst: property):
pass
def POP(self, dst: property):
pass
def INC(self, dst: property):
pass
def DEC(self, dst: property):
pass
def JP(self, dst: property, src: property):
pass
def JR(self, dst: property, src: property):
pass
def CALL(self, dst: property, src: property):
pass
def IN(self, dst: property, src: property):
pass
def OUT(self, dst: property, src: property):
pass
def EX(self, dst: property, src: property):
pass
import reg
class z80opcodes(reg.z80regs):
pass
def LD8_12(self, dst: property, src: property):
dst.fset(self, src.fget(self))
def LD8_21(self, src: property, dst: property):
self.LD8_12(dst, src)
def LD16_12(self, src: property, dst: property):
dst.fset(self, src.fget(self))
def LD16_21(self, dst: property, src: property):
self.LD16_12(dst, src)
def ADD(self, to: property, v: property):
to.fset(self, to.fget(self) + v.fget(self))
def _flags_for_result(self, v):
self._flags.s = 1 if v < 0 else 0
self._flags.z = 1 if v != 0 else 0
def INC(self, reg: property):
r = reg.fget(self)+1
reg.fset(self, r)
self._flags_for_result(r)
def DEC(self, reg: property):
r = reg.fget(self)-1
reg.fset(self, r)
self._flags_for_result(r)
def CP(self, reg: property, v: property): pass
def NOP(self): pass
def HALT(self): pass
def RLC(self, reg: property): pass
def RRC(self, reg: property): pass
def RR(self, reg: property): pass
def RL(self, reg: property): pass
def DAA(self): pass
def CPL(self, reg: property): pass
def CALL(self, c: int, v: property): pass
def RET(self, c: int): pass
def JP(self, c: int, v: property): pass
def JR(self, c: int, v: property): pass
def swap_any(self, r1: property, r2: property): pass
from typing import Callable, Optional
class _rawflagregister(object):
s = 0
z = 0
x5 = 0
h = 0
x3 = 0
pv = 0
n = 0
c = 0
class _rawregisters(object):
a = 0
b = 0
c = 0
d = 0
e = 0
h = 0
l = 0
i = 0
r = 0
sp = 0
pc = 0
ix = 0
iy = 0
class _context(object):
hook_ix = False
hook_iy = False
class z80regs(object):
_regs = _rawregisters()
_flags = _rawflagregister
_ctx = _context()
#_ctx.hook_ix = False
#_ctx.hook_iy = False
@property
def a(self):
return self._regs.a
@a.setter
def a_set(self, v: int):
self._regs.a = v & 0xff
@property
def b(self):
return self._regs.b
@b.setter
def b_set(self, v: int):
self._regs.b = v & 0xff
@property
def c(self):
return self._regs.c
@c.setter
def c_set(self, v: int):
self._regs.c = v & 0xff
@property
def d(self):
return self._regs.d
@d.setter
def d_set(self, v: int):
self._regs.d = v & 0xff
@property
def e(self):
return self._regs.e
@e.setter
def e_set(self, v: int):
self._regs.e = v & 0xff
@property
def h(self):
if self._ctx.hook_ix:
return (self._regs.ix >> 8) & 0xff
if self._ctx.hook_iy:
return self._regs.iy & 0xff
return self._regs.h
@h.setter
def h_set(self, v: int):
self._regs.h = v & 0xff
@property
def l(self):
if self._ctx.hook_ix:
return (self._regs.iy >> 8)
if self._ctx.hook_iy:
return self._regs.iy & 0xff
return self._regs.l
@l.setter
def l_set(self, v: int):
self._regs.l = v & 0xff
@property
def bc(self):
return self._regs.b << 8 + self._regs.c
@bc.setter
def bc_set(self, v: int):
self._regs.c = v & 0xff
self._regs.b = v >> 8
@property
def de(self):
return self.d << 8 + self._regs.e
@de.setter
def de_set(self, v: int):
self.e = v & 0xff
self.d = v >> 8
@property
def hl(self):
if self._ctx.hook_ix:
return self.ix
if self._ctx.hook_iy:
return self.iy
return self.h << 8 + self._regs.l
@hl.setter
def hl_set(self, v: int):
if self._ctx.hook_ix:
self.ix = v
return
if self._ctx.hook_iy:
self.iy = v
return
self.l = v & 0xff
self.h = v >> 8
@property
def ix(self):
return self._regs.ix
@ix.setter
def ix_set(self, v):
self._regs.ix = v & 0xffff
@property
def iy(self):
return self._regs.ix
@iy.setter
def iy_set(self, v):
self._regs.iy = v & 0xffff
@property
def sp(self):
return self._regs.sp
@sp.setter
def sp_set(self, v: int):
self._regs.sp = v & 0xff
@property
def af(self):
pass
@property
def f(self):
return ((self._flags.s << 7) +
(self._flags.z << 6) +
(self._flags.h << 4) +
(self._flags.pv << 2) +
(self._flags.n << 1) +
(self._flags.c))
@f.setter
def f_set(self, value):
self._flags.s = (value << 7) & 1
self._flags.z = (value << 6) & 1
self._flags.h = (value << 4) & 1
self._flags.pv = (value << 2) & 1
self._flags.n = (value << 1) & 1
self._flags.c = (value) & 1
@property
def f_c(self):
return self._flags.c
@f_c.setter
def f_c_set(self, value):
self._flags.c = value & 1
@property
def at_bc(self): pass
@property
def at_de(self): pass
@property
def at_hl(self): pass
@property
def at_sp(self): pass
@property
def i(self):
return self._regs.i
@property
def r(self):
return self._regs.r
@property
def NZ(self):
return self._flags.z == 0
@property
def Z(self):
return self._flags.z == 1
@property
def NC(self):
return self._flags.c == 0
@property
def C(self):
return self._flags.c == 1
@property
def PO(self):
return self._flags.pv == 0
@property
def PE(self):
return self._flags.pv == 1
@property
def P(self):
return self._flags.n == 0
@property
def M(self):
return self._flags.n == 1
def mergedict(org: dict, add: tuple) -> dict:
newer = dict(org.items())
newer.update({add[0]: add[1]})
return newer
reg8 = {
0b111: z80regs.a,
0b000: z80regs.b,
0b001: z80regs.c,
0b010: z80regs.d,
0b011: z80regs.e,
0b100: z80regs.h,
0b101: z80regs.l,
}
reg8_110at_hl = mergedict(reg8, (0b110, z80regs.at_hl))
reg16 = {
0b00: z80regs.bc,
0b01: z80regs.de,
0b10: z80regs.hl,
0b11: z80regs.sp,
}
reg16_11af = mergedict(reg16, (0b11, z80regs.af))
cond = {
0b000: z80regs.NZ,
0b001: z80regs.Z,
0b010: z80regs.NC,
0b011: z80regs.C,
0b100: z80regs.PO,
0b101: z80regs.PE,
0b110: z80regs.P,
0b111: z80regs.M,
}
import inspect
from typing import Optional, List
import reg
import oper
import _stubs
class context_0(reg._context):
instr = []
offset = 0
ipos = 0
ptrpos = 0
class instr_1b(oper.z80opcodes, _stubs.stubs):
shadow = reg.z80regs()
_ctx = context_0()
@property
def mainreg(self):
return self._regs
@property
def shadowreg(self):
return self.shadow
def _fetch_next_1b(self):
pass
def _fetch_1b(self,addr:int):
pass
@property
def i8(self) -> int:
return self._fetch_next_1b()
@property
def i16(self):
return self._fetch_next_1b() + (self._fetch_next_1b() << 8)
@property
def at_16(self):
return self._fetch_1b( self.i16() )
@property
def at_nn(self): pass
reg8 = reg.reg8
reg16 = reg.reg16
cond = reg.cond
reg8_110at_hl = reg.reg8_110at_hl
reg16_11af = reg.reg16_11af
def _sw_IX(self):
self._ctx.hook_ix = True
def _sw_IY(self):
self._ctx.hook_iy = True
def _reset_ctx(self):
self._ctx.hook_ix = False
self._ctx.hook_iy = False
@classmethod
def what(cls, who: object) -> str:
for cls1 in inspect.getmro(cls):
for kk, vv in cls1.__dict__.items():
if vv == who:
return cls.__name__ + "." + kk
return None
# print(dir(z80))
# print(z80.__subclasscheck__())
# print(inspect.getmro(z80))
# class z80(object):
# print(t.reg8)
# print(t.reg8_110at_hl)
# print(t.reg16)
# print(t.reg16_af)
def expand_1b(bmap: list):
mask = 0
datum = 0
r = 0
lsn = 0
def iter(bmap: list):
yield (bmap[0], bmap[1][0])
for nn in range(1, len(bmap[1])):
yield (bmap[nn+1], bmap[1][nn])
bias = []
for vv, bn in iter(bmap[0]):
# print(vv)
# print(bn)
for bb in range(0, len(bias)):
bias[bb][0] = bias[bb][0] << lsn
r = r << lsn
mask += (1 << bn) - 1
datum += vv if type(vv) == int else 0
if type(vv) == dict:
k = [x for x in vv.keys()]
k.sort()
bias.append([1, k])
lsn = bn
return [(mask, datum), dict(bias)]
# http://www.yamamo10.jp/yamamoto/comp/Z80/instructions/index.php
z80_1b = instr_1b
_decode_0: list = [
[[0b00, [2, 2, 4], 0b10, 0b0010], [z80_1b.LD16_12, z80_1b.hl, z80_1b.at_16]],
[[0b00, [2, 2, 4], 0b10, 0b1010], [z80_1b.LD16_21, z80_1b.hl, z80_1b.at_16]],
[[0b00, [2, 2, 4], z80_1b.reg16, 0b0011], [z80_1b.INC, 1]],
[[0b00, [2, 2, 4], z80_1b.reg16, 0b1001], [z80_1b.ADD, z80_1b.hl, 1]],
[[0b00, [2, 2, 4], z80_1b.reg16, 0b1011], [z80_1b.DEC, 1]],
[[0b00, [2, 3, 3], 0b110, 0b110], [z80_1b.LD8_21, z80_1b.at_hl, z80_1b.i8]],
[[0b00, [2, 3, 3], z80_1b.reg8, 0b101], [z80_1b.DEC, 1]],
[[0b00, [2, 3, 3], z80_1b.reg8, 0b110], [z80_1b.INC, 1]],
[[0b00, [2, 3, 3], z80_1b.reg8, 0b110], [z80_1b.LD8_21, 1, z80_1b.i8]],
[[0b00, [2, 3, 3], {0b000: z80_1b.at_bc, 0b010: z80_1b.at_de,
0b110: z80_1b.at_nn}, 0b010], [z80_1b.LD8_21, 1, z80_1b.a]],
[[0b00, [2, 3, 3], {0b001: z80_1b.at_bc, 0b011: z80_1b.at_de,
0b111: z80_1b.at_nn}, 0b010], [z80_1b.LD8_12, 1, z80_1b.a]],
[[0b00, [2, 3, 3], {0b011: None, 0b111: z80_1b.C, 0b110: z80_1b.NC,
0b101: z80_1b.Z, 0b100: z80_1b.NC}, 0b000], [instr_1b.JR, 1, z80_1b.i8]],
[[0b00000000, [8]], [z80_1b.NOP]],
[[0b00000111, [8]], [z80_1b.RLC, z80_1b.a]],
[[0b00001000, [8]], [z80_1b.swap_any, z80_1b.af, "None"]],
[[0b00001111, [8]], [z80_1b.RRC, z80_1b.a]],
[[0b00010000, [8]], [instr_1b.JR, "--B", z80_1b.i8]],
[[0b00010111, [8]], [z80_1b.RL, z80_1b.a]],
[[0b00011111, [8]], [z80_1b.RR, z80_1b.a]],
[[0b00100100, [8]], [instr_1b.INC, z80_1b.at_hl]],
[[0b00100111, [8]], [z80_1b.DAA]],
[[0b00101111, [8]], [z80_1b.CPL, z80_1b.a]],
[[0b00110101, [8]], [z80_1b.DEC, z80_1b.at_hl]],
[[0b00110111, [8]], ["SCF", z80_1b.f_c, 1]],
[[0b00111111, [8]], ["CCF", z80_1b.f_c, 0]],
[[0b01, [2, 2, 4], z80_1b.reg16, 0b0001], [z80_1b.LD16_21, 1, z80_1b.i16]],
[[0b01, [2, 3, 3], 0b110, z80_1b.reg8], [z80_1b.LD8_21, z80_1b.at_hl, 2]],
[[0b01, [2, 3, 3], z80_1b.reg8, 0b110], [z80_1b.LD8_21, 1, z80_1b.at_hl]],
[[0b01, [2, 3, 3], z80_1b.reg8, z80_1b.reg8], [z80_1b.LD8_21, 1, 2]],
[[0b01110, [5, 3], 0b110], [z80_1b.HALT]],
[[0b10, [2, 3, 3], 0b000, z80_1b.reg8_110at_hl], [instr_1b.ADD, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b001, z80_1b.reg8_110at_hl], [instr_1b.ADC, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b010, z80_1b.reg8_110at_hl], [instr_1b.SUB, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b011, 0b110], [instr_1b.SBC, z80_1b.a, z80_1b.at_hl]],
[[0b10, [2, 3, 3], 0b011, z80_1b.reg8], [instr_1b.SUB, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b100, z80_1b.reg8_110at_hl], [instr_1b.AND, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b101, z80_1b.reg8_110at_hl], [instr_1b.XOR, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b110, 0b110], [instr_1b.OR, z80_1b.a, z80_1b.at_hl]],
[[0b10, [2, 3, 3], 0b110, z80_1b.reg8_110at_hl], [instr_1b.OR, z80_1b.a, 1]],
[[0b10, [2, 3, 3], 0b111, 0b110], [z80_1b.CP, z80_1b.a, z80_1b.at_hl]],
[[0b10, [2, 3, 3], 0b111, z80_1b.reg8_110at_hl], [z80_1b.CP, z80_1b.a, 1]],
[[0b11, [2, 2, 4], z80_1b.reg16_11af, 0b0001], [instr_1b.POP, 1]],
[[0b11, [2, 2, 4], z80_1b.reg16_11af, 0b0101], [instr_1b.PUSH, 1]],
[[0b11, [2, 3, 3], z80_1b.cond, 0b000], [z80_1b.RET, 1]],
[[0b11, [2, 3, 3], z80_1b.cond, 0b010], [instr_1b.JP, 1, z80_1b.i16]],
[[0b11, [2, 3, 3], z80_1b.cond, 0b100], [instr_1b.CALL, 1, z80_1b.i16]],
[[0b11000, [5, 3], 0b110], [instr_1b.ADD, z80_1b.a, z80_1b.i8]],
[[0b11000011, [8]], [instr_1b.JP, None, z80_1b.i16]],
[[0b11001001, [8]], [z80_1b.RET, None]],
[[0b11001011, [8]], ["BIT/SET/RES"]],
[[0b11001011, [8]], ["SLA/SRA/R[RL]|C r|(HL)"]],
[[0b11001101, [8]], [instr_1b.CALL, "None", z80_1b.i16]],
[[0b11010, [5, 3], 0b110], [instr_1b.SUB, z80_1b.a, z80_1b.i8]],
[[0b11010011, [8]], [instr_1b.OUT, z80_1b.a, z80_1b.i8]],
[[0b11011011, [8]], [instr_1b.IN, z80_1b.a, z80_1b.i8]],
[[0b11011101, [8]], ["IX"]],
[[0b11100, [5, 3], 0b110], [instr_1b.AND, z80_1b.a, z80_1b.i8]],
[[0b11100011, [8]], [z80_1b.swap_any, z80_1b.mainreg, z80_1b.shadowreg]],
[[0b11100011, [8]], [z80_1b.swap_any, z80_1b.at_sp, z80_1b.hl]],
[[0b11101, [5, 3], 0b110], [instr_1b.XOR, z80_1b.a, z80_1b.at_hl]],
[[0b11101001, [8]], [instr_1b.JP, None, z80_1b.hl]],
[[0b11101011, [8]], [z80_1b.swap_any, z80_1b.de, z80_1b.hl]],
[[0b11101101, [8]], ["OUT(C)/OUTI/OUTD/OUTDR"]],
[[0b11101101, [8]], ["ADC|SBC|NEG"]],
[[0b11101101, [8]], ["CPI/CPIR/CPD/CPDR"]],
[[0b11101101, [8]], ["IN/INI/INIR/IND/INDR"]],
[[0b11101101, [8]], ["LD I/R/R16"]],
[[0b11101101, [8]], ["LDI/LDIR/LDD/LDDR"]],
[[0b11101101, [8]], ["RLD/RRD"]],
[[0b11110, [5, 3], 0b110], [instr_1b.OR, z80_1b.a, z80_1b.i8]],
[[0b11111, [5, 3], 0b110], [z80_1b.CP, z80_1b.a, z80_1b.i8]],
[[0b11111001, [8]], [z80_1b.LD16_12, z80_1b.sp, z80_1b.hl]],
[[0b11111101, [8]], ["IY"]]
]
import seq_0
class z80(seq_0.instr_1b):
pass
_decode_0 = seq_0._decode_0
expand_1b = seq_0.expand_1b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment