#!/usr/bin/python USAGE = """ Usage: %s h8.lst 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, "\ticount = 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, "\ticount = 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))