mirror of
https://github.com/holub/mame
synced 2025-05-04 21:43:05 +03:00

h8: Fix problem in the sleep instruction [O. Galibert] at45dbxx: Fix communications [O. Galibert]
470 lines
17 KiB
Python
470 lines
17 KiB
Python
#!/usr/bin/python
|
|
|
|
USAGE = """
|
|
Usage:
|
|
%s h8.lst <type> h8.inc (type = o/h/s20/s26)
|
|
"""
|
|
import sys
|
|
|
|
def name_to_type(name):
|
|
if(name == "o"):
|
|
return 0
|
|
if(name == "h"):
|
|
return 1
|
|
if(name == "s20"):
|
|
return 2
|
|
if(name == "s26"):
|
|
return 3
|
|
print "Unknown chip type name %s" % name
|
|
sys.exit(1)
|
|
|
|
def type_to_device(dtype):
|
|
if(dtype == 0):
|
|
return "h8_device"
|
|
if(dtype == 1):
|
|
return "h8h_device"
|
|
if(dtype == 2):
|
|
return "h8s2000_device"
|
|
return "h8s2600_device"
|
|
|
|
def hexsplit(str):
|
|
res = []
|
|
for i in range(0, len(str), 2):
|
|
res.append(int(str[i:i+2], 16))
|
|
return res
|
|
|
|
def has_memory(ins):
|
|
for s in ["read", "write", "sp_push", "sp_pop", "sp32_push", "sp32_pop", "fetch(", "prefetch_start(", "prefetch(", "prefetch_noirq("]:
|
|
if s in ins:
|
|
return True
|
|
return False
|
|
|
|
def has_eat(ins):
|
|
if "eat-all-cycles" in ins:
|
|
return True
|
|
return False
|
|
|
|
def save_full_one(f, t, name, source):
|
|
print >>f, "void %s::%s_full()" % (t, name)
|
|
print >>f, "{"
|
|
substate = 1
|
|
for line in source:
|
|
if has_memory(line):
|
|
print >>f, "\tif(icount <= bcount) { inst_substate = %d; return; }" % substate
|
|
print >>f, line
|
|
substate = substate + 1
|
|
elif has_eat(line):
|
|
print >>f, "\tif(icount) icount = bcount; inst_substate = %d; return;" % substate
|
|
substate = substate + 1
|
|
else:
|
|
print >>f, line
|
|
print >>f, "}"
|
|
print >>f
|
|
|
|
def save_partial_one(f, t, name, source):
|
|
print >>f, "void %s::%s_partial()" % (t, name)
|
|
print >>f, "{"
|
|
print >>f, "switch(inst_substate) {"
|
|
print >>f, "case 0:"
|
|
substate = 1
|
|
for line in source:
|
|
if has_memory(line):
|
|
print >>f, "\tif(icount <= bcount) { inst_substate = %d; return; }" % substate
|
|
print >>f, "case %d:;" % substate
|
|
print >>f, line
|
|
substate = substate + 1
|
|
elif has_eat(line):
|
|
print >>f, "\tif(icount) icount = bcount; inst_substate = %d; return;" % substate
|
|
print >>f, "case %d:;" % substate
|
|
substate = substate + 1
|
|
else:
|
|
print >>f, line
|
|
print >>f, "\tbreak;"
|
|
print >>f, "}"
|
|
print >>f, "\tinst_substate = 0;"
|
|
print >>f, "}"
|
|
print >>f
|
|
|
|
class Hash:
|
|
def __init__(self, premask):
|
|
self.mask = 0x00
|
|
self.enabled = False
|
|
self.premask = premask
|
|
self.d = {}
|
|
|
|
def get(self, val, premask):
|
|
if val in self.d:
|
|
h = self.d[val]
|
|
if h.premask != premask:
|
|
print "Premask conflict"
|
|
sys.exit(1)
|
|
return h
|
|
h = Hash(premask)
|
|
self.d[val] = h
|
|
return h
|
|
|
|
def set(self, val, opc):
|
|
if val in self.d:
|
|
print "Collision on %s" % opc.description()
|
|
sys.exit(1)
|
|
self.d[val] = opc
|
|
|
|
class Opcode:
|
|
def __init__(self, val, mask, skip, name, am1, am2, otype, dtype):
|
|
self.name = name
|
|
self.val = hexsplit(val)
|
|
self.mask = hexsplit(mask)
|
|
self.skip = int(skip)
|
|
self.am1 = am1
|
|
self.am2 = am2
|
|
self.source = []
|
|
self.otype = otype
|
|
self.enabled = otype == -1 or (otype == 0 and dtype == 0) or (otype != 0 and dtype >= otype)
|
|
self.needed = self.enabled and (otype == dtype or (otype == -1 and dtype == 0))
|
|
if dtype == 0 and (am1 == "r16l" or am2 == "r16l"):
|
|
self.mask[len(self.mask)-1] = self.mask[len(self.mask)-1] | 0x08
|
|
if dtype == 0 and (am1 == "r16h" or am2 == "r16h"):
|
|
self.mask[len(self.mask)-1] = self.mask[len(self.mask)-1] | 0x80
|
|
extra_words = 0
|
|
if (am1 == "abs16" or am2 == "abs16" or am1 == "abs16e" or am1 == "abs24e") and self.skip == 0:
|
|
extra_words = extra_words + 1
|
|
if (am1 == "abs32" or am2 == "abs32") and self.skip == 0:
|
|
extra_words = extra_words + 2
|
|
if am1 == "imm16" or am1 == "rel16" or am1 == "r16d16h" or am2 == "r16d16h" or am1 == "r32d16h" or am2 == "r32d16h":
|
|
extra_words = extra_words + 1
|
|
if am1 == "imm32" or am1 == "r32d32hh" or am2 == "r32d32hh":
|
|
extra_words = extra_words + 2
|
|
self.extra_words = extra_words
|
|
base_offset = len(self.val)/2 + self.skip
|
|
for i in range(0, extra_words):
|
|
self.source.append("\tfetch(%d);\n" % (i+base_offset));
|
|
|
|
def description():
|
|
return "%s %s %s" % (self.name, self.am1, self.am2)
|
|
|
|
def add_source_line(self, line):
|
|
self.source.append(line)
|
|
|
|
def is_dispatch(self):
|
|
return False
|
|
|
|
def function_name(self):
|
|
n = self.name.replace(".", "_")
|
|
if self.am1 != "-":
|
|
n = n + "_" + self.am1
|
|
if self.am2 != "-":
|
|
n = n + "_" + self.am2
|
|
return n
|
|
|
|
def save_dasm(self, f):
|
|
if len(self.mask) == 2:
|
|
mask = (self.mask[0] << 8) | self.mask[1]
|
|
val = (self.val[0] << 8) | self.val[1]
|
|
mask2 = 0
|
|
val2 = 0
|
|
slot = 0
|
|
elif len(self.mask) == 4:
|
|
mask = (self.mask[0] << 24) | (self.mask[1] << 16) | (self.mask[2] << 8) | self.mask[3]
|
|
val = (self.val[0] << 24) | (self.val[1] << 16) | (self.val[2] << 8) | self.val[3]
|
|
mask2 = 0
|
|
val2 = 0
|
|
slot = self.skip + 1
|
|
else:
|
|
mask = (self.mask[2] << 24) | (self.mask[3] << 16) | (self.mask[4] << 8) | self.mask[5]
|
|
val = (self.val[2] << 24) | (self.val[3] << 16) | (self.val[4] << 8) | self.val[5]
|
|
mask2 = (self.mask[0] << 8) | self.mask[1]
|
|
val2 = (self.val[0] << 8) | self.val[1]
|
|
slot = 4
|
|
|
|
size = len(self.val) + 2*self.skip + 2*self.extra_words
|
|
|
|
if self.name == "jsr" or self.name == "bsr":
|
|
flags = "%d | DASMFLAG_STEP_OVER" % size
|
|
elif self.name == "rts" or self.name == "rte":
|
|
flags = "%d | DASMFLAG_STEP_OUT" % size
|
|
else:
|
|
flags = "%d" % size
|
|
|
|
print >>f, "\t{ %d, 0x%08x, 0x%08x, 0x%04x, 0x%04x, \"%s\", DASM_%s, DASM_%s, %s }, // %s" % ( slot, val, mask, val2, mask2, self.name, self.am1 if self.am1 != "-" else "none", self.am2 if self.am2 != "-" else "none", flags, "needed" if self.needed else "inherited")
|
|
|
|
class Special:
|
|
def __init__(self, val, name, otype, dtype):
|
|
self.name = name
|
|
self.val = int(val, 16)
|
|
self.enabled = otype == -1 or (otype == 0 and dtype == 0) or (otype != 0 and dtype >= otype)
|
|
self.needed = otype == dtype or (otype == -1 and dtype == 0)
|
|
self.source = []
|
|
|
|
def add_source_line(self, line):
|
|
self.source.append(line)
|
|
|
|
class Macro:
|
|
def __init__(self, tokens):
|
|
self.name = tokens[1]
|
|
self.params = []
|
|
for i in range(2, len(tokens)):
|
|
self.params.append(tokens[i])
|
|
self.source = []
|
|
|
|
def add_source_line(self, line):
|
|
self.source.append(line)
|
|
|
|
def apply(self, target, tokens):
|
|
values = []
|
|
if len(self.params) > 1:
|
|
for i in range(0, len(self.params)-1):
|
|
values.append(tokens[i+1])
|
|
lval = ""
|
|
for i in range(len(self.params)-1, len(tokens)-1):
|
|
if lval != "":
|
|
lval = lval + " "
|
|
lval = lval + tokens[i+1]
|
|
values.append(lval)
|
|
for i in range(0, len(self.source)):
|
|
line = self.source[i]
|
|
for i in range(0, len(self.params)):
|
|
line = line.replace(self.params[i], values[i])
|
|
target.add_source_line(line)
|
|
|
|
class DispatchStep:
|
|
def __init__(self, id, pos, opc):
|
|
self.id = id
|
|
self.pos = pos
|
|
self.name = ""
|
|
self.enabled = False
|
|
self.mask = opc.mask[pos-1]
|
|
for i in range(0, pos):
|
|
self.name = self.name + ("%02x" % opc.val[i])
|
|
if pos == 2:
|
|
self.skip = opc.skip
|
|
else:
|
|
self.skip = 0
|
|
|
|
def is_dispatch(self):
|
|
return True
|
|
|
|
def source(self):
|
|
start = self.pos / 2
|
|
end = start + self.skip
|
|
s = []
|
|
for i in range(start, end+1):
|
|
s.append("\tIR[%d] = fetch();" % i)
|
|
s.append("\tinst_state = 0x%x0000 | IR[%d];" % (self.id, end))
|
|
return s;
|
|
|
|
class OpcodeList:
|
|
def __init__(self, fname, dtype):
|
|
self.opcode_info = []
|
|
self.dispatch_info = []
|
|
self.states_info = []
|
|
self.dispatch = {}
|
|
self.macros = {}
|
|
try:
|
|
f = open(fname, "r")
|
|
except Exception, err:
|
|
print "Cannot read opcodes file %s [%s]" % (fname, err)
|
|
sys.exit(1)
|
|
|
|
opc = None
|
|
for line in f:
|
|
if line.startswith("#"):
|
|
continue
|
|
line = line.rstrip()
|
|
if not line:
|
|
continue
|
|
if line.startswith(" ") or line.startswith("\t"):
|
|
if inf != None:
|
|
# append instruction to last opcode, maybe expand a macro
|
|
tokens = line.split()
|
|
if tokens[0] in self.macros:
|
|
self.macros[tokens[0]].apply(inf, tokens)
|
|
else:
|
|
inf.add_source_line(line)
|
|
else:
|
|
# New opcode
|
|
tokens = line.split()
|
|
if tokens[0] == "macro":
|
|
inf = Macro(tokens)
|
|
self.macros[inf.name] = inf
|
|
elif len(tokens) == 2 or len(tokens) == 3:
|
|
if len(tokens) >= 3:
|
|
otype = name_to_type(tokens[2])
|
|
else:
|
|
otype = -1
|
|
inf = Special(tokens[0], tokens[1], otype, dtype)
|
|
self.states_info.append(inf)
|
|
else:
|
|
if len(tokens) >= 7:
|
|
otype = name_to_type(tokens[6])
|
|
else:
|
|
otype = -1
|
|
if otype == -1 or dtype == 0 or (otype != 0 and dtype != 0):
|
|
inf = Opcode(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5], otype, dtype)
|
|
self.opcode_info.append(inf)
|
|
else:
|
|
inf = None
|
|
|
|
def get(self, i):
|
|
if i in self.dispatch:
|
|
return self.dispatch[i]
|
|
h = Hash(0)
|
|
self.dispatch[i] = h
|
|
return h
|
|
|
|
def build_dispatch(self):
|
|
for opc in self.opcode_info:
|
|
for i in range(0, len(opc.val)):
|
|
v = opc.val[i]
|
|
if i == 0:
|
|
h = self.get(0)
|
|
if opc.enabled:
|
|
h.mask = h.mask | opc.mask[i]
|
|
h.enabled = True
|
|
if (i & 1) == 0:
|
|
h = h.get(v, opc.mask[i])
|
|
elif i == len(opc.val)-1:
|
|
if opc.enabled:
|
|
h.set(v, opc)
|
|
else:
|
|
if v in h.d:
|
|
d = h.d[v]
|
|
if not d.is_dispatch():
|
|
print "Collision on %s" % opc.description()
|
|
sys.exit(1)
|
|
if opc.enabled:
|
|
d.enabled = True
|
|
h = self.get(d.id)
|
|
else:
|
|
d = DispatchStep(len(self.dispatch_info)+2, i+1, opc)
|
|
self.dispatch_info.append(d)
|
|
if opc.enabled:
|
|
d.enabled = True
|
|
h.set(v, d)
|
|
h = self.get(d.id)
|
|
|
|
def save_dasm(self, f, dname):
|
|
print >>f, "const %s::disasm_entry %s::disasm_entries[] = {" % (dname, dname)
|
|
for opc in self.opcode_info:
|
|
if opc.enabled:
|
|
opc.save_dasm(f)
|
|
print >>f, "\t{ 0, 0, 0, 0, 0, \"illegal\", 0, 0, 2 },"
|
|
print >>f, "};"
|
|
print >>f
|
|
|
|
def save_opcodes(self, f, t):
|
|
for opc in self.opcode_info:
|
|
if opc.needed:
|
|
save_full_one(f, t, opc.function_name(), opc.source)
|
|
save_partial_one(f, t, opc.function_name(), opc.source)
|
|
|
|
for sta in self.states_info:
|
|
if sta.needed:
|
|
save_full_one(f, t, "state_" + sta.name, sta.source)
|
|
save_partial_one(f, t, "state_" + sta.name, sta.source)
|
|
|
|
def save_dispatch(self, f, t):
|
|
for dsp in self.dispatch_info:
|
|
save_full_one(f, t, "dispatch_" + dsp.name, dsp.source())
|
|
save_partial_one(f, t, "dispatch_" + dsp.name, dsp.source())
|
|
|
|
def save_exec(self, f, t, dtype, v):
|
|
print >>f, "void %s::do_exec_%s()" % (t, v)
|
|
print >>f, "{"
|
|
print >>f, "\tswitch(inst_state >> 16) {"
|
|
for i in range(0, len(self.dispatch_info)+2):
|
|
if i == 1:
|
|
print >>f, "\tcase 0x01: {"
|
|
print >>f, "\t\tswitch(inst_state & 0xffff) {"
|
|
for sta in self.states_info:
|
|
if sta.enabled:
|
|
print >>f, "\t\tcase 0x%02x: state_%s_%s(); break;" % (sta.val & 0xffff, sta.name, v)
|
|
print >>f, "\t\t}"
|
|
print >>f, "\t\tbreak;"
|
|
print >>f, "\t}"
|
|
else:
|
|
if i == 0 or self.dispatch_info[i-2].enabled:
|
|
print >>f, "\tcase 0x%02x: {" % i
|
|
h = self.get(i)
|
|
print >>f, "\t\tswitch((inst_state >> 8) & 0x%02x) {" % h.mask
|
|
for val, h2 in sorted(h.d.items()):
|
|
if h2.enabled:
|
|
fmask = h2.premask | (h.mask ^ 0xff)
|
|
c = ""
|
|
s = 0
|
|
while(s < 0x100):
|
|
c = c + "case 0x%02x: " % (val | s)
|
|
s = s + 1
|
|
while(s & fmask):
|
|
s = s + (s & fmask)
|
|
print >>f, "\t\t%s{" % c
|
|
if h2.mask == 0x00:
|
|
n = h2.d[0]
|
|
if n.is_dispatch():
|
|
print >>f, "\t\t\tdispatch_%s_%s();" % (n.name, v)
|
|
else:
|
|
print >>f, "\t\t\t%s_%s();" % (n.function_name(), v)
|
|
print >>f, "\t\t\tbreak;"
|
|
else:
|
|
print >>f, "\t\t\tswitch(inst_state & 0x%02x) {" % h2.mask
|
|
if i == 0:
|
|
mpos = 1
|
|
else:
|
|
mpos = self.dispatch_info[i-2].pos + 1
|
|
for val2, n in sorted(h2.d.items()):
|
|
if n.enabled:
|
|
fmask = h2.mask ^ 0xff
|
|
if n.is_dispatch():
|
|
fmask = fmask | n.mask
|
|
else:
|
|
fmask = fmask | n.mask[mpos]
|
|
c = ""
|
|
s = 0
|
|
while(s < 0x100):
|
|
c = c + "case 0x%02x: " % (val2 | s)
|
|
s = s + 1
|
|
while(s & fmask):
|
|
s = s + (s & fmask)
|
|
if n.is_dispatch():
|
|
print >>f, "\t\t\t%sdispatch_%s_%s(); break;" % (c, n.name, v)
|
|
else:
|
|
print >>f, "\t\t\t%s%s_%s(); break;" % (c, n.function_name(), v)
|
|
print >>f, "\t\t\tdefault: illegal(); break;"
|
|
print >>f, "\t\t\t}"
|
|
print >>f, "\t\t\tbreak;"
|
|
print >>f, "\t\t}"
|
|
print >>f, "\t\tdefault: illegal(); break;"
|
|
print >>f, "\t\t}"
|
|
print >>f, "\t\tbreak;"
|
|
print >>f, "\t}"
|
|
print >>f, "\t}"
|
|
print >>f, "}"
|
|
|
|
def main(argv):
|
|
if len(argv) != 4:
|
|
print USAGE % argv[0]
|
|
return 1
|
|
|
|
dtype = name_to_type(argv[2])
|
|
dname = type_to_device(dtype)
|
|
opcodes = OpcodeList(argv[1], dtype)
|
|
|
|
try:
|
|
f = open(argv[3], "w")
|
|
except Exception, err:
|
|
logging.error("cannot write file %s [%s]", fname, err)
|
|
sys.exit(1)
|
|
|
|
opcodes.build_dispatch()
|
|
opcodes.save_dasm(f, dname)
|
|
opcodes.save_opcodes(f, dname)
|
|
if dtype == 0:
|
|
opcodes.save_dispatch(f, dname)
|
|
opcodes.save_exec(f, dname, dtype, "full")
|
|
opcodes.save_exec(f, dname, dtype, "partial")
|
|
f.close()
|
|
|
|
# ======================================================================
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv))
|
|
|