├── .gitignore ├── README ├── bitmap.py ├── const.py ├── cpu_x86.py ├── cpus ├── __init__.py ├── arm.py ├── arm_thumb2_instructions.txt ├── arm_thumb3_instructions.txt ├── arm_thumb_instructions.txt ├── cdp1802.py ├── m68000.py ├── m68000_instructions.txt ├── m68010_instructions.txt ├── m68020_instructions.txt ├── m68030_instructions.txt ├── m68040_instructions.txt ├── m68881_instructions.txt ├── mc6800.py ├── mcs4.py ├── mcs48.py ├── mcs48_instructions.txt ├── mcs4_instructions.txt ├── mcs51.py ├── mcs51_instructions.txt ├── mcs6500.py ├── nova.py ├── nova_instructions.txt ├── z80.py ├── z8000.py ├── z8000_instructions.txt └── z80_instructions.txt ├── disass.py ├── domus ├── __init__.py ├── const.py ├── cpu.py ├── desc.py ├── do_file.py ├── domus_funcs.txt ├── domus_page_zero.txt ├── hints │ ├── CATW_CATW.py │ ├── DOMUS_S0303.py │ ├── INT_INT14.py │ ├── LIBE_OBJ00.py │ ├── MUC_MUC03.py │ ├── MUSIL_CMP10.py │ └── __init__.py ├── inter │ ├── __init__.py │ ├── inter.py │ └── lib.py ├── libs.py ├── mem.py ├── rd_mupar.py ├── reloc_file.py └── syscall.py ├── explore.py ├── file_elf.py ├── instree.py ├── mem.py ├── model.py ├── notes ├── pyreveng.py ├── render.py ├── tasks ├── cbm900 │ ├── EPROM_C_900_boot-H_V_1.0.bin │ ├── EPROM_C_900_boot-L_V_1.0.bin │ └── task.py ├── cbm900_fd │ ├── EPROM_Z8000_Fl.Cont._S41_6-20-85.bin │ └── task.py ├── cbm900_wdc │ ├── MCU_WDC_U10.bin │ └── task.py ├── cdp1802_test │ ├── cdp1802.bin │ └── task.py ├── domus │ ├── __.CATLI │ └── task.py ├── mc6800_hp53xx │ ├── HP5359A.ROM │ ├── HP5370A.ROM │ ├── HP5370B.ROM │ ├── hp5370.py │ ├── hp53xx.py │ ├── task_hp5359a.py │ ├── task_hp5370a.py │ └── task_hp5370b.py ├── mcs4_micrologic_ml200 │ ├── P1702.hex │ ├── P8316.hex │ ├── pseudo.py │ └── task.py ├── z8000_test │ ├── task.py │ ├── u91.bin │ ├── u92.bin │ ├── u93.bin │ └── u94.bin └── z80_rc702_bootrom │ ├── EPROM_ROA_375.bin │ └── task.py ├── topology.py └── tree.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.orig 3 | *.rej 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | NOTICE (2019-11-11) 3 | =================== 4 | 5 | This project is retired, please see the successor project: 6 | 7 | https://github.com/bsdphk/PyReveng3 8 | 9 | Poul-Henning 10 | 11 | Original README content 12 | ----------------------- 13 | 14 | This is the latest instantiation of a long series of programable 15 | reverse engineering/disassembly tools I have written. Python seems 16 | to work so well for this kind of work that I am trying to write a 17 | general-purpose toolkit this time, which does not depend on a 18 | particular memory layout, CPU architecture or for that matter 19 | anything else. 20 | 21 | For now, we are limited to 32 bits of memory width, but should 22 | pythons array type grow a 64 bit subtype, we can go higher. 23 | 24 | A good place to start is: 25 | 26 | cd tasks/mc6800_hp53xx 27 | python3.2 task_hp5370b.py 28 | less /tmp/_.hp5370b.txt 29 | 30 | A much more advanced example can be found in: 31 | 32 | cd tasks/domus 33 | python3.2 task.py 34 | less /tmp/_.CATLI_OBJ00.txt 35 | 36 | Enjoy, 37 | 38 | Poul-Henning 39 | -------------------------------------------------------------------------------- /bitmap.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | class bitmap(object): 5 | def __init__(self, low = 0, high = None): 6 | assert type(low) == int 7 | self.low = low 8 | self.high = high 9 | assert high == None or type(high) == int 10 | if self.high == None: 11 | self.mem = bytearray() 12 | else: 13 | assert high > low 14 | w = ((high - low) | 7) + 1 15 | self.mem = bytearray(w >> 3) 16 | 17 | def set(self, n): 18 | assert type(n) == int 19 | assert n >= self.low 20 | n -= self.low 21 | if self.high != None: 22 | assert n <= self.high 23 | b = n >> 3 24 | i = 0x80 >> (n & 7) 25 | 26 | if self.high == None and len(self.mem) <= b: 27 | self.mem += bytearray(b + 1 - len(self.mem)) 28 | self.mem[b] |= i 29 | 30 | def mset(self, lo, hi): 31 | for i in range(lo, hi): 32 | self.set(i) 33 | 34 | def clr(self, n): 35 | assert type(n) == int 36 | assert n >= self.low 37 | n -= self.low 38 | if self.high != None: 39 | assert n <= self.high 40 | b = n >> 3 41 | i = 0x80 >> (n & 7) 42 | 43 | if self.high == None and len(self.mem) <= b: 44 | self.mem += bytearray(b + 1 - len(self.mem)) 45 | self.mem[b] &= ~i 46 | 47 | def mclr(self, lo, hi): 48 | for i in range(lo, hi): 49 | self.clr(i) 50 | 51 | def tst(self, n): 52 | assert type(n) == int 53 | assert n >= self.low 54 | n -= self.low 55 | if self.high != None: 56 | assert n <= self.high 57 | b = n >> 3 58 | i = 0x80 >> (n & 7) 59 | 60 | if self.high == None and len(self.mem) <= b: 61 | return False 62 | return (self.mem[b] & i) == i 63 | 64 | def mtst(self, lo, hi): 65 | l = self.tst(lo) 66 | for i in range(lo, hi): 67 | if self.tst(i) != l: 68 | return None 69 | return l 70 | -------------------------------------------------------------------------------- /const.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | from struct import unpack, pack 7 | 8 | import tree 9 | 10 | 11 | class byte(tree.tree): 12 | def __init__(self, p, adr, len = 1, fmt="0x%02x"): 13 | tree.tree.__init__(self, adr, adr + len, "const") 14 | p.t.add(self.start, self.end, self.tag, True, self) 15 | 16 | self.render = self.rfunc 17 | self.fmt = fmt 18 | 19 | def rfunc(self, p, t): 20 | s = ".BYTE\t" 21 | d = "" 22 | for i in range(t.start, t.end): 23 | x = p.m.rd(i) 24 | s += d 25 | s += self.fmt % x 26 | d = ", " 27 | return (s,) 28 | 29 | class w16(tree.tree): 30 | def __init__(self, p, adr, len = 1, fmt="0x%04x"): 31 | tree.tree.__init__(self, adr, adr + len * 2, "const") 32 | p.t.add(self.start, self.end, self.tag, True, self) 33 | 34 | self.render = self.rfunc 35 | self.fmt = fmt 36 | 37 | def rfunc(self, p, t): 38 | s = ".WORD\t" 39 | d = "" 40 | for i in range(t.start, t.end, 2): 41 | x = p.m.w16(i) 42 | s += d 43 | s += self.fmt % x 44 | d = ", " 45 | return (s,) 46 | 47 | class w32(tree.tree): 48 | def __init__(self, p, adr, len = 1, fmt="0x%08x"): 49 | tree.tree.__init__(self, adr, adr + len * 4, "const") 50 | p.t.add(self.start, self.end, self.tag, True, self) 51 | 52 | self.render = self.rfunc 53 | self.fmt = fmt 54 | 55 | def rfunc(self, p, t): 56 | s = ".LWORD\t" 57 | d = "" 58 | for i in range(t.start, t.end, 4): 59 | x = p.m.w32(i) 60 | s += d 61 | s += self.fmt % x 62 | d = ", " 63 | return (s,) 64 | 65 | class ptr(tree.tree): 66 | def __init__(self, p, adr, width = 2, len = 1): 67 | tree.tree.__init__(self, adr, adr + len * width, "const") 68 | p.t.add(self.start, self.end, self.tag, True, self) 69 | 70 | self.render = self.rfunc 71 | self.width = width 72 | 73 | def rfunc(self, p, t): 74 | s = ".PTR\t" 75 | d = "" 76 | for i in range(t.start, t.end, self.width): 77 | if self.width == 2: 78 | x = p.m.w16(i) 79 | elif self.width == 4: 80 | x = p.m.w32(i) 81 | else: 82 | assert self.width == "Wrong width" 83 | s += d 84 | if x in p.label: 85 | s += p.label[x] 86 | else: 87 | s += p.m.afmt(x) 88 | d = ", " 89 | return (s,) 90 | 91 | class ieee_fp64(tree.tree): 92 | def __init__(self, p, adr, endian=">"): 93 | tree.tree.__init__(self, adr, adr + 8, "ieee_fp64") 94 | p.t.add(self.start, self.end, self.tag, True, self) 95 | 96 | self.render = self.rfunc 97 | b = bytearray() 98 | for i in range(8): 99 | b.append(p.m.rd(adr + i)) 100 | self.fp = unpack(endian + "d", b) 101 | 102 | def rfunc(self, p, t): 103 | return (".FP64\t%.15g" % self.fp,) 104 | 105 | class ltxt(tree.tree): 106 | def __init__(self, p, adr, align=2): 107 | l = p.m.rd(adr) 108 | len = l + 1 109 | len += align - 1 110 | len &= ~(align -1) 111 | tree.tree.__init__(self, adr, adr + len, "const") 112 | p.t.add(self.start, self.end, self.tag, True, self) 113 | 114 | self.render = self.rfunc 115 | self.l = l 116 | self.txt = p.m.ascii(adr + 1, l) 117 | 118 | def rfunc(self, p, t): 119 | s = ".LTXT\t%d,'" % self.l + self.txt + "'" 120 | return (s,) 121 | 122 | class txtlen(tree.tree): 123 | def __init__(self, p, adr, len, align=1): 124 | llen = len + align - 1 125 | llen &= ~(align -1) 126 | tree.tree.__init__(self, adr, adr + llen, "const") 127 | p.t.add(self.start, self.end, self.tag, True, self) 128 | 129 | self.render = self.rfunc 130 | self.txt = p.m.ascii(adr, len) 131 | 132 | def rfunc(self, p, t): 133 | s = ".TXT\t'" + self.txt + "'" 134 | return (s,) 135 | 136 | class txt(tree.tree): 137 | def __init__(self, p, adr, len = None, align=1): 138 | elen = 0 139 | self.term="" 140 | if len == None: 141 | len = 0; 142 | while True: 143 | c = p.m.rd(adr + len) 144 | if c == 0x00: 145 | self.term=",0" 146 | elen = 1 147 | break; 148 | len += 1 149 | if c != 0x0a: 150 | continue 151 | # We treat newlines special: 152 | # If it looks like text continues 153 | # start another instance on the next line 154 | # XXX: means length don't match, bad! 155 | c2 = p.m.rd(adr + len) 156 | if c2 == 0x0a or c2 == 0x00: 157 | continue 158 | txt(p, adr + len) 159 | break; 160 | if len <= 0: 161 | print("BOGUS const.txt @%x" % adr) 162 | return 163 | if align == 2 and (adr+len+elen) & 1: 164 | elen += 1 165 | tree.tree.__init__(self, adr, adr + len + elen, "const") 166 | x = p.t.add(self.start, self.end, self.tag, True, self) 167 | 168 | self.render = self.rfunc 169 | if len > 0: 170 | self.txt = p.m.ascii(adr, len) 171 | else: 172 | self.txt = "" 173 | 174 | def rfunc(self, p, t): 175 | s = ".TXT\t'" + self.txt + "'" + self.term 176 | return (s,) 177 | 178 | class fill(tree.tree): 179 | def __init__(self, p, lo = None, mid = None, hi = None, fmt = None, rd = None): 180 | if rd == None: 181 | rd = p.m.rd 182 | if fmt == None: 183 | fmt = p.m.dpct 184 | if lo == None: 185 | if mid != None: 186 | lo = mid 187 | elif hi != None: 188 | lo = hi 189 | else: 190 | print("BOGUS fill(", lo, ",", mid, ",", hi, ")") 191 | return 192 | x = rd(lo) 193 | while x == rd(lo - 1): 194 | lo -= 1 195 | if hi == None: 196 | if mid != None: 197 | hi = mid 198 | elif lo != None: 199 | hi = lo 200 | else: 201 | print("BOGUS fill(", lo, ",", mid, ",", hi, ")") 202 | return 203 | x = rd(hi) 204 | try: 205 | while x == rd(hi + 1): 206 | hi += 1 207 | except: 208 | pass 209 | hi += 1 210 | if lo == None or hi == None: 211 | print("BOGUS fill(", lo, ",", mid, ",", hi, ")") 212 | return 213 | tree.tree.__init__(self, lo, hi, "fill") 214 | x = p.t.add(self.start, self.end, self.tag, True, self) 215 | x.render = ".Fill\t" + \ 216 | fmt % rd(lo) + "[" + fmt % (hi-lo) + "]" 217 | x.fold = True 218 | 219 | def seven_seg_lcmt(y, val, map = ( 1, 2, 4, 8, 16, 32, 64, 128, 0)): 220 | if val & map[0]: 221 | y.lcmt(" --") 222 | else: 223 | y.lcmt(" ") 224 | 225 | if val & map[5]: 226 | s = " |" 227 | else: 228 | s = " " 229 | if val & map[1]: 230 | y.lcmt(s + " |") 231 | else: 232 | y.lcmt(s + " ") 233 | 234 | if val & map[6]: 235 | y.lcmt(" --") 236 | else: 237 | y.lcmt(" ") 238 | 239 | if val & map[4]: 240 | s = " |" 241 | else: 242 | s = " " 243 | if val & map[2]: 244 | y.lcmt(s + " |") 245 | else: 246 | y.lcmt(s + " ") 247 | 248 | if val & map[8]: 249 | s = "." 250 | else: 251 | s = " " 252 | if val & map[3]: 253 | s += " -- " 254 | else: 255 | s += " " 256 | if val & map[7]: 257 | y.lcmt(s + ".") 258 | else: 259 | y.lcmt(s) 260 | y.lcmt(" ") 261 | 262 | class seven_segment(tree.tree): 263 | def __init__(self, p, adr, 264 | map = ( 1, 2, 4, 8, 16, 32, 64, 128, 0)): 265 | tree.tree.__init__(self, adr, adr + 1, "7seg") 266 | y = p.t.add(self.start, self.end, self.tag, True, self) 267 | val = p.m.rd(adr) 268 | y.render = ".BYTE 0x%02x" % val 269 | seven_seg_lcmt(y, val, map) 270 | -------------------------------------------------------------------------------- /cpus/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cpus/arm.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | import const 7 | import disass 8 | import instree 9 | 10 | cond_code = ( 11 | "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", 12 | "HI", "LS", "GE", "LT", "GT", "LE", "T", "F" 13 | ) 14 | 15 | class arm(disass.assy): 16 | """ 17 | """ 18 | 19 | def __init__(self, p, name = "arm", arch="cortex-m3"): 20 | disass.assy.__init__(self, p, name) 21 | self.thumb_root = instree.instree( 22 | width=16, 23 | filename = __file__[:-3] + "_thumb_instructions.txt" 24 | ) 25 | self.thumb_root.load (__file__[:-3] + "_thumb2_instructions.txt") 26 | self.thumb_root.load (__file__[:-3] + "_thumb3_instructions.txt") 27 | self.arch = arch 28 | self.thumb_root.print() 29 | 30 | def disass(self, adr, priv=None): 31 | a0 = adr & ~1 32 | ins = disass.assy.disass(self, a0, priv) 33 | if adr & 1: 34 | ins.thumb = True 35 | else: 36 | ins.thumb = False 37 | return ins 38 | 39 | def do_disass(self, adr, ins): 40 | #assert ins.lo == adr 41 | assert ins.status == "prospective" 42 | 43 | if ins.thumb: 44 | self.do_thumb(adr, ins) 45 | else: 46 | self.do_thumb(adr, ins) 47 | #assert ins.thumb 48 | 49 | def do_arm(self, adr, ins): 50 | return 51 | 52 | 53 | def thumb_field(self, p, c, adr, fld): 54 | return c.get_field(p, adr, p.m.l16, 2, fld) 55 | 56 | def do_thumb(self, adr, ins): 57 | 58 | p = self.p 59 | iw = p.m.b16(adr) 60 | # XXX: below needed ? 61 | ins.oper = list() 62 | try: 63 | c = self.thumb_root.find(p, adr, p.m.l16) 64 | except: 65 | ins.mne = "???" 66 | ins.hi = ins.lo + 2 67 | return 68 | print("IW %08x %04x" % (adr, iw), c) 69 | 70 | if iw == 0: 71 | ins.mne = "???" 72 | ins.hi = ins.lo + 2 73 | return 74 | 75 | ins.mne = c.spec[0] 76 | 77 | na = adr + (c.width >> 3) 78 | 79 | for i in c.spec[1].split(","): 80 | if i == "simm11": 81 | da = self.thumb_field(p, c, adr, i) 82 | da = da << 1 83 | if da & 0x0800: 84 | da -= 4096 85 | da = da + 4 + adr 86 | ins.oper.append((da, "0x%08x" % da)) 87 | ins.flow("cond", "T", da) 88 | elif i == "[SP+imm8l*4]": 89 | da = self.thumb_field(p, c, adr, "imm8l") 90 | da = da << 2 91 | ins.oper.append(("[SP,#0x%x]" % da)) 92 | elif i == "[PC+imm8l*4]": 93 | da = self.thumb_field(p, c, adr, "imm8l") 94 | da = da << 2 95 | da += (adr & ~3) + 4 96 | ins.oper.append((da, "0x%08x" % da)) 97 | const.w32(p,da) 98 | elif i == "[Rn+Rm]": 99 | rn = self.thumb_field(p, c, adr, "Rn") 100 | rm = self.thumb_field(p, c, adr, "Rm") 101 | ins.oper.append("[R%d,R%d]" % (rn, rm)) 102 | elif i == "[Rn+imm5]": 103 | da = self.thumb_field(p, c, adr, "imm5") 104 | rn = self.thumb_field(p, c, adr, "Rn") 105 | ins.oper.append("[R%d,#0x%x]" % (rn, da)) 106 | elif i == "[Rn+imm5w*2]": 107 | da = self.thumb_field(p, c, adr, "imm5w") 108 | rn = self.thumb_field(p, c, adr, "Rn") 109 | ins.oper.append("[R%d,#0x%x]" % (rn, da << 1)) 110 | elif i == "[Rn+imm5l*4]": 111 | da = self.thumb_field(p, c, adr, "imm5l") 112 | rn = self.thumb_field(p, c, adr, "Rn") 113 | ins.oper.append("[R%d,#0x%x]" % (rn, da << 2)) 114 | elif i == "Rd" or i == "Rm" or i == "Rn": 115 | da = self.thumb_field(p, c, adr, i) 116 | ins.oper.append("R%d" % da) 117 | elif i == "RdH": 118 | r = self.thumb_field(p, c, adr, "Rd") 119 | if self.thumb_field(p, c, adr, "H"): 120 | r += 8 121 | ins.oper.append("R%d" % r) 122 | elif i == "Rmh": 123 | r = self.thumb_field(p, c, adr, "Rm") 124 | if self.thumb_field(p, c, adr, "h"): 125 | r += 8 126 | ins.oper.append("R%d" % r) 127 | ins.flow("cond", "T", None) 128 | elif i == "imm7l" or i == "imm8l": 129 | da = self.thumb_field(p, c, adr, i) 130 | ins.oper.append("#0x%x" % (da << 2)) 131 | elif i == "imm8" or i == "imm5" or i == "imm3": 132 | da = self.thumb_field(p, c, adr, i) 133 | ins.oper.append("#0x%x" % da) 134 | elif i == "simm8": 135 | da = self.thumb_field(p, c, adr, i) 136 | if da & 0x80: 137 | da -= 256 138 | da = da << 1 139 | da += adr + 4 140 | ins.oper.append((da, "0x%08x" % da)) 141 | elif i == "cond": 142 | cc = self.thumb_field(p, c, adr, i) 143 | da = ins.oper[-1][0] 144 | if ins.mne == "B": 145 | ins.flow("cond", cond_code[cc], da) 146 | if cc != 14: 147 | ins.flow("cond", cond_code[cc ^ 1], adr + 2) 148 | ins.mne += cond_code[cc] 149 | elif i == "bl_tgt": 150 | da = self.thumb_field(p, c, adr, "off11_a") 151 | da = da << 12 152 | if da & 0x400000: 153 | da |= 0xff800000 154 | da += (adr & ~3) + 4 155 | db = self.thumb_field(p, c, adr, "off11_b") 156 | da += db << 1 157 | da = da & 0xffffffff 158 | ins.oper.append((da, "0x%08x" % da)) 159 | if ins.mne == "BL": 160 | ins.flow("call", "T", da) 161 | elif i == "regs": 162 | l = list() 163 | r = self.thumb_field(p, c, adr, i) 164 | for i in range(0,8): 165 | if r & (1 << i): 166 | l.append("R%d" % i) 167 | r = self.thumb_field(p, c, adr, "R") 168 | if r: 169 | l.append("LR") 170 | ins.oper.append("{" + ",".join(l) + "}") 171 | elif i == "SP": 172 | ins.oper.append(i) 173 | else: 174 | try: 175 | arg = self.thumb_field(p,c, adr, i) 176 | except: 177 | arg = None 178 | ins.oper.append(i) 179 | print(">>>", i, arg) 180 | ins.flow("ret", "T", None) 181 | 182 | ins.hi = na 183 | print("==", ins, ins.mne, ins.oper) 184 | -------------------------------------------------------------------------------- /cpus/arm_thumb2_instructions.txt: -------------------------------------------------------------------------------- 1 | # ARM "Thumb2" instruction set 2 | # 3 | # Taken from: 4 | # ARM Architecture Reference Manual / ARM DDI 0100I 5 | # ARM Architecture Reference Manual Thumb-2 Supplement / ARM DDI 0308D 6 | # 7 | # Conventions: 8 | # H1 = H 9 | # H2 = h 10 | # #*4 = imm8l 11 | # #*2 = imm7w 12 | # 13 | # |X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X|X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X| 14 | # --------------------------------- 15 | # These are in v5+Thumb 16 | BKPT imm8 |1 0 1 1 1 1 1 0| imm8 | 17 | BLX bl_tgt |1 1 1 1 0| off11_a |1 1 1 0 1| off11_b | 18 | # --------------------------------- 19 | # These are in v6k+Thumb 20 | # --------------------------------- 21 | CLREX c |1 1 1 1 0|0|1 1 1|0 1|1|1 1 1 1|1 0|0|0|1 1 1 1|0 0 1 0|1 1 1 1| 22 | # --------------------------------- 23 | # These are in v7+Thumb 24 | # --------------------------------- 25 | DMB c |1 1 1 1 0|0|1 1 1|0 1|1|1 1 1 1|1 0|0|0|1 1 1 1|0 1 0 1| opt | 26 | DSB c |1 1 1 1 0|0|1 1 1|0 1|1|1 1 1 1|1 0|0|0|1 1 1 1|0 1 0 0| opt | 27 | ISB c |1 1 1 1 0|0|1 1 1|0 1|1|1 1 1 1|1 0|0|0|1 1 1 1|0 1 1 0| opt | 28 | # --------------------------------- 29 | # These are true "Thumb2" 30 | ADC Sc,Rd,Rn,imm |1 1 1 1 0|i|0|1 0 1 0|S| Rn |0|imm3 | Rd | imm8 | 31 | ADC Sc,W,Rd,Rn,Rm,r |1 1 1 0 1|0 1|1 0 1 0|S| Rn |0|imm3 | Rd |im2|tpe| Rm | 32 | ADD Sc,W,Rd,Rn,imm |1 1 1 1 0|i|0|1 0 0 0|S| Rn |0|imm3 | Rd | imm8 | 33 | ADDW c,Rd,Rn,imm12 |1 1 1 1 0|i|1|0 0 0 0|0| Rn |0|imm3 | Rd | imm8 | 34 | ADD Sc,W,Rd,Rn,Rm,r |1 1 1 0 1|0 1|1 0 0 0|S| Rn |0|imm3 | Rd |im2|tpe| Rm | 35 | ADD Sc,W,Rd,SP,imm |1 1 1 1 0|i|0|1 0 0 0|S|1 1 0 1|0|imm3 | Rd | imm8 | 36 | ADDW c,Rd,SP,imm |1 1 1 1 0|i|1|0 0 0 0|0|1 1 0 1|0|imm3 | Rd | imm8 | 37 | ADD Sc,W,Rd,Sp,Rm,r |1 1 1 0 1 0 1 1 0 0 0|S|1 1 0 1|0|imm3 | Rd |im2|tpe| Rm | 38 | ADR c,W,Rd,dstb |1 1 1 1 0|i|1 0 1 0 1|0|1 1 1 1|0|imm3 | Rd | imm8 | 39 | ADR c,W,Rd,dsta |1 1 1 1 0|i|1 0 0 0 0|0|1 1 1 1|0|imm3 | Rd | imm8 | 40 | AND Sc,Rd,Rn,imm |1 1 1 1 0|i|0 0 0 0 0|S| Rn |0|imm3 | Rd | imm8 | 41 | AND Sc,W,Rd,Rn,Rm,r |1 1 1 0 1|0 1|0 0 0 0|S| Rn |0|imm3 | Rd |im2|tpe| Rm | 42 | ASR Sc,W,Rd,Rm,imm5 |1 1 1 0 1|0 1|0 0 1 0|S|1 1 1 1|0|imm3 | Rd |im2|1 0| Rm | 43 | ASR Sc,W,Rd,Rn,Rm |1 1 1 1 1|0 1 0|0|1 0|S| Rn |1 1 1 1| Rd |0|0 0 0| Rm | 44 | B c,W,dst |1 1 1 1 0|S| cond | imm6 |1 0|j|0|J| imm11 | 45 | B c,W,dst |1 1 1 1 0|S| imm10 |1 0|j|1|J| imm11 | 46 | BFC c,Rd,lsb,wid |1 1 1 1 0|0|1 1|0 1 1|0|1 1 1 1|0|imm3 | Rd |im2|0| msb | 47 | BFI c,Rd,Rn,lsb,wid |1 1 1 1 0|0|1 1|0 1 1|0| Rn |0|imm3 | Rd |im2|0| msb | 48 | BIC Sc,Rd,Rn,im |1 1 1 1 0|i|9 9 9 9 1|S| Rn |0|imm3 | Rd | imm8 | 49 | BIC Sc,W,Rd,Rn,Rm,r |1 1 1 0 1|0 1|0 0 0 1|S| Rn |0|imm3 | Rd |im2|tpe| Rm | 50 | BL c,bl_tgt2 |1 1 1 1 0|S| imm10 |1 1|J|1|j| imm11 | 51 | BLX c,bl_tgt2 |1 1 1 1 0|S| imm10h |1 1|J|0|j| imm10l |0| 52 | BXJ c,Rm |1 1 1 1 0|0|1 1 1 1|0 0| Rm |1 0|0|0|1 1 1 1|0 0 0 0 0 0 0 0| 53 | CBNZ Rn,dst |1 0 1 1|1|0|i|1| imm5 | Rn | 54 | CBZ Rn,dst |1 0 1 1|0|0|1|1| imm5 | Rn | 55 | CDP coproc |1 1 1|C|1 1 1 0| opc1 | CRn | Crd | coproc| opc2|0| CRm | 56 | CLZ c,Rd,Rm |1 1 1 1 1|0 1 0|1|0 1 1| Rm2 |1 1 1 1| Rd |1|0 0 0| Rm | 57 | CMN Rn,immi38 |1 1 1 1 0|i|0|1 0 0 0|1| Rn |0|imm3 |1 1 1 1| imm8 | 58 | CMN c,W,Rn,Rm,r |1 1 1 0 1|0 1|1 0 0 0|1| Rn |0|imm3 |1 1 1 1|im2|tpe| Rm | 59 | CMP c,W,Rn,inti38 |1 1 1 1 0|i|0|1 1 0 1|1| Rn |0|imm3 |1 1 1 1| imm 8 | 60 | CMP c,W,Rn,Rm,r |1 1 1 0 1|0 1|1 1 0 1|1| Rn |0|imm3 |1 1 1 1|im2|tpe| Rm | 61 | CPS eff,ifl |1 0 1 1|0 1 1 0|0 1 1|i|0|A|I|F| 62 | CPS eff,W,ifl,mod |1 1 1 1 0|0|1 1 1 0|1 0|1 1 1 1|1 0|0|0|0|imd|M|A|I|F| mode | 63 | DBG c,opt |1 1 1 1 0|0|1 1 1|0 1|0|1 1 1 1|1 0|0|0|0|0 0 0|1 1 1 1| opt | 64 | EOR Sc,Rd,Rn,inti38 |1 1 1 1 0|i|0|0 1 0 0|S| Rn |0|imm3 | Rd | imm8 | 65 | EOR Sc,W,Rd,Rn,Rm,r |1 1 1 0 1|0 1|0 1 0 0|S| Rn |0|imm3 | Rd |im2|tpe| Rm | 66 | IT X,Y,Z,1cond |1 0 1 1|1 1 1 1| 1cond | mask | 67 | LDC coproc |1 1 1|C|1 1 0|P|U|N|W|1| Rn | CRd | coproc| imm8 | 68 | LDMDB Rn!,regs |1 1 1 0 1|0 0|1 0 0|W|1| Rn |P|M|0| regs | 69 | LDMIA c,W,Rn!,regs |1 1 1 0 1|0 0|0 1 0|W|1| Rn |P|M|0| regs | 70 | LDR c,W,Rt,[Rn+i12] |1 1 1 1 1|0 0|0|1|1 0|1| Rn | Rt | imm12 | 71 | LDR c,Rt,[Rn+imm8] |1 1 1 1 1|0 0|0|0|1 0|1| Rn | Rt |1|P|U|W| imm8 | 72 | LDR c,W,Rt,[PC+i12] |1 1 1 1 1|0 0|0|U|1 0|1|1 1 1 1| Rt | imm12 | 73 | LDR c,W,Rt,[Rn+RmL] |1 1 1 1 1|0 0|0|0|1 0|1| Rn | Rt |0|0 0 0 0 0|sh | Rm | 74 | # ... ARM DDI0308D 4-106 75 | -------------------------------------------------------------------------------- /cpus/arm_thumb3_instructions.txt: -------------------------------------------------------------------------------- 1 | # ARM "Thumb3" instruction set 2 | # 3 | # Taken from: 4 | # ARM Architecture Reference Manual 5 | # ARM DDI 0100I 6 | # 7 | # Conventions: 8 | # H1 = H 9 | # H2 = h 10 | # #*4 = imm8l 11 | # #*2 = imm7w 12 | # 13 | # |X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X| 14 | # --------------------------------- 15 | # See note p.A7-41 16 | #CPY Rd,Rm |0 1 0 0 0 1 1 0|H|h| Rm | Rd | 17 | REV Rd,Rn |1 0 1 1 1 0 1 0|0|0| Rn | Rd | 18 | REV16 Rd,Rn |1 0 1 1|1 0 1 0|0 1| Rn | Rd | 19 | REVSH Rd,Rn |1 0 1 1|1 0 1 0|1 1| Rn | Rd | 20 | SETEND E |1 0 1 1|0 1 1 0 0 1 0 1|E|0 0 0| 21 | SXTB Rd,Rm |1 0 1 1|0 0 1 0|0 1| Rm | Rd | 22 | SXTH Rd,Rm |1 0 1 1|0 0 1 0|0 0| Rm | Rd | 23 | UXTB Rd,Rm |1 0 1 1|0 0 1 0|1 1| Rm | Rd | 24 | UXTH Rd,Rm |1 0 1 1|0 0 1 0|1 0| Rm | Rd | 25 | # --------------------------------- 26 | -------------------------------------------------------------------------------- /cpus/arm_thumb_instructions.txt: -------------------------------------------------------------------------------- 1 | # ARM "Thumb" instruction set 2 | # 3 | # Taken from: 4 | # ARM Architecture Reference Manual 5 | # ARM DDI 0100E 6 | # 7 | # 8 | # Conventions: 9 | # H1 = H 10 | # H2 = h 11 | # #*4 = imm8l 12 | # #*2 = imm7w 13 | # 14 | # |X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X| 15 | # --------------------------------- 16 | ADC Rd,Rm |0 1 0 0 0 0|0 1 0 1| Rm | Rd | 17 | ADD Rd,Rn,imm3 |0 0 0 1 1 1 0| imm3| Rn | Rd | 18 | ADD Rd,imm8 |0 0 1 1 0| Rd | imm8 | 19 | ADD Rd,Rn,Rm |0 0 0 1 1 0 0| Rm | Rn | Rd | 20 | ADD Rd,Rm |0 1 0 0 0 1 0 0|H|h| Rm | Rd | 21 | ADD Rd,PC,imm8l |1 0 1 0 0| Rd | imm8l | 22 | ADD Rd,SP,imm8l |1 0 1 0 1| Rd | imm8l | 23 | ADD SP,imm7l |1 0 1 1 0 0 0 0 0| imm7l | 24 | AND Rd,Rm |0 1 0 0 0 0|0 0 0 0| Rm | Rd | 25 | ASR Rd,Rm,imm5 |0 0 0 1 0| imm5 | Rm | Rd | 26 | ASR Rd,Rs |0 1 0 0 0 0|0 1 0 0| Rs | Rd | 27 | B simm8,cond |1 1 0 1| cond | simm8 | 28 | B simm11 |1 1 1 0 0| simm11 | 29 | BIC Rd,Rm |0 1 0 0 0 0|1 1 1 0| Rm | Rd | 30 | BL bl_tgt |1 1 1 1 0| off11_a |1 1 1 1 1| off11_b | 31 | BX Rmh |0 1 0 0 0 1 1 1 0|h| Rm |0 0 0| 32 | CMN Rn,Rm |0 1 0 0 0 0|1 0 1 1| Rm | Rd | 33 | CMP Rn,imm8 |0 0 1 0 1| Rn | imm8 | 34 | CMP Rn,Rm |0 1 0 0 0 0|1 0 1 0| Rm | Rn | 35 | CMP Rn,Rm |0 1 0 0 0 1 0 1|H|h| Rmh | RnH | 36 | EOR Rd,Rm |0 1 0 0 0 0|0 0 0 1| Rm | Rd | 37 | LDMIA Rn!,regs |1 1 0 0 1| Rn | regs | 38 | LDR Rd,[Rn+imm5l*4] |0 1 1 0 1| imm5l | Rn | Rd | 39 | LDR Rd,[Rn+Rm] |0 1 0 1 1 0 0| Rm | Rn | Rd | 40 | LDR Rd,[PC+imm8l*4] |0 1 0 0 1| Rd | imm8l | 41 | LDR Rd,[SP+imm8l*4] |1 0 0 1 1| Rd | imm8l | 42 | LDRB Rd,[Rn+imm5] |0 1 1 1 1| imm5 | Rn | Rd | 43 | LDRB Rd,[Rn+Rm] |0 1 0 1 1 1 0| Rm | Rn | Rd | 44 | LDRH Rd,[Rn+imm5w*2] |1 0 0 0 1| imm5w | Rn | Rd | 45 | LDRH Rd,[Rn+Rm] |0 1 0 1 1 0 1| Rm | Rn | Rd | 46 | LDRSB Rd,[Rn+Rm] |0 1 0 1 0 1 1| Rm | Rn | Rd | 47 | LDRSH Rd,[Rn+Rm] |0 1 0 1 1 1 1| Rm | Rn | Rd | 48 | LSL Rd,Rm,imm5 |0 0 0 0 0| imm5 | Rm | Rd | 49 | LSL Rd,Rs |0 1 0 0 0 0|0 0 1 0| Rs | Rd | 50 | LSR Rd,Rm,imm5 |0 0 0 0 1| imm5 | Rm | Rd | 51 | LSR Rd,Rs |0 1 0 0 0 0|0 0 1 1| Rs | Rd | 52 | MOV Rd,imm8 |0 0 1 0 0| Rd | imm8 | 53 | MOV Rd,Rn |0 0 0 1 1 1 0|0 0 0| Rn | Rd | 54 | MOV RdH,Rmh |0 1 0 0 0 1 1 0|H|h| Rm | Rd | 55 | MUL Rd,Rm |0 1 0 0 0 0|1 1 0 1| Rm | Rd | 56 | MVN Rd,Rm |0 1 0 0 0 0|1 1 1 1| Rm | Rd | 57 | NEG Rd,Rm |0 1 0 0 0 0|1 0 0 1| Rm | Rd | 58 | ORR Rd,Rm |0 1 0 0 0 0|1 1 0 0| Rm | Rd | 59 | POP regs |1 0 1 1 1 1 0|R| regs | 60 | PUSH regs |1 0 1 1 0 1 0|R| regs | 61 | ROR Rd,Rs |0 1 0 0 0 0|0 1 1 1| Rs | Rd | 62 | SBC Rd,Rm |0 1 0 0 0 0|0 1 1 0| Rm | Rd | 63 | STMIA Rn!,regs |1 1 0 0 0| Rn | regs | 64 | STR Rd,[Rn+imm5l*4] |0 1 1 0 0| imm5l | Rn | Rd | 65 | STR Rd,[Rn+Rm] |0 1 0 1 0 0 0| Rm | Rn | Rd | 66 | STR Rd,[SP+imm8l*4] |1 0 0 1 0| Rd | imm8l | 67 | STRB Rd,[Rn+imm5] |0 1 1 1 0| imm5 | Rn | Rd | 68 | STRB Rd,[Rn+Rm] |0 1 0 1 0 1 0| Rm | Rn | Rd | 69 | STRH Rd,[Rn+imm5w*2] |1 0 0 0 0| imm5w | Rn | Rd | 70 | STRH Rd,[Rn+Rm] |0 1 0 1 0 0 1| Rm | Rn | Rd | 71 | SUB Rd,Rn,imm3 |0 0 0 1 1 1 1| imm3| Rn | Rd | 72 | SUB Rd,imm8 |0 0 1 1 1| Rd | imm8 | 73 | SUB Rd,Rn,Rm |0 0 0 1 1 0 1| Rm | Rn | Rd | 74 | SUB SP,imm7l |1 0 1 1 0 0 0 0 1| imm7l | 75 | SWI imm8 |1 1 0 1 1 1 1 1| imm8 | 76 | TST Rn,Rm |0 1 0 0 0 0|1 0 0 0| Rm | Rn | 77 | 78 | -------------------------------------------------------------------------------- /cpus/m68010_instructions.txt: -------------------------------------------------------------------------------- 1 | # 68010 instruction list 2 | # 3 | # From: 4 | # M68000 Family Programmer's Reference Manual 5 | # 6 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 7 | # 476/6-22 8 | mOVEC Rc,Dn 0000 |0 1 0 0|1 1 1 0|0 1 1 1|1 0 1|0|0| Dn | Rc | 9 | mOVEC Rc,An 0000 |0 1 0 0|1 1 1 0|0 1 1 1|1 0 1|0|1| An | Rc | 10 | mOVEC Dn,Rc 0000 |0 1 0 0|1 1 1 0|0 1 1 1|1 0 1|1|0| Dn | Rc | 11 | MOVEC An,Rc 0000 |0 1 0 0|1 1 1 0|0 1 1 1|1 0 1|1|1| An | Rc | 12 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 13 | -------------------------------------------------------------------------------- /cpus/m68020_instructions.txt: -------------------------------------------------------------------------------- 1 | # 68020 instruction list 2 | # 3 | # From: 4 | # M68000 Family Programmer's Reference Manual 5 | # 6 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 7 | # 196/4.92 8 | DIVS.L ea,Dx,Dy 1f7d |0 1 0 0 1 1 0 0 0 1| eam | ear |0| Dy |1|0|0 0 0 0 0 0 0| Dx | 9 | DIVSL.L ea,Dx,Dy 1f7d |0 1 0 0 1 1 0 0 0 1| eam | ear |0| Dy |1|1|0 0 0 0 0 0 0| Dx | 10 | # 200/4.96 11 | DIVU.L ea,Dx,Dy 1f7d |0 1 0 0 1 1 0 0 0 1| eam | ear |0| Dy |0|0|0 0 0 0 0 0 0| Dx | 12 | DIVUL.L ea,Dx,Dy 1f7d |0 1 0 0 1 1 0 0 0 1| eam | ear |0| Dy |0|1|0 0 0 0 0 0 0| Dx | 13 | # 210/4.106 14 | EXTB.L Dn 0 |0 1 0 0 1 0 0 1 1 1 0 0 0| Dn | 15 | # 239/4.135 16 | MULS.L ea,Dy 1f7d |0 1 0 0 1 1 0 0 0 0| eam | ear |0| Dy |1|0|0 0 0 0 0 0 0| Dx | 17 | mULS.L ea,Dx,Dy 1f7d |0 1 0 0 1 1 0 0 0 0| eam | ear |0| Dy |1|1|0 0 0 0 0 0 0| Dx | 18 | # 242/4.138 19 | mULU.L ea,Dy 1f7d |0 1 0 0 1 1 0 0 0 0| eam | ear |0| Dy |0|0|0 0 0 0 0 0 0| Dx | 20 | mULU.L ea,Dx,Dy 1f7d |0 1 0 0 1 1 0 0 0 0| eam | ear |0| Dy |0|1|0 0 0 0 0 0 0| Dx | 21 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 22 | -------------------------------------------------------------------------------- /cpus/m68030_instructions.txt: -------------------------------------------------------------------------------- 1 | # 68030 instruction list 2 | # 3 | # From: 4 | # M68000 Family Programmer's Reference Manual 5 | # 6 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 7 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 8 | -------------------------------------------------------------------------------- /cpus/m68040_instructions.txt: -------------------------------------------------------------------------------- 1 | # 68040 instruction list 2 | # 3 | # From: 4 | # M68000 Family Programmer's Reference Manual 5 | # 6 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 7 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 8 | -------------------------------------------------------------------------------- /cpus/m68881_instructions.txt: -------------------------------------------------------------------------------- 1 | # 68020 instruction list 2 | # 3 | # From: 4 | # M68000 Family Programmer's Reference Manual 5 | # 6 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 7 | # 468/6.14 8 | FSAVE ea 372 |1 1 1 1|0 0 1|1 0 0| eam | ear | 9 | # src,dst ea |_ _ _ _|_ _ _v_|_ _v_ _|_v_ _ _|_ _ _ _|_ _ _ _|_ _ _ _|_ _ _ _| 10 | -------------------------------------------------------------------------------- /cpus/mc6800.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Motorola 6800 CPU disassembler 4 | # 5 | 6 | from __future__ import print_function 7 | 8 | import const 9 | import disass 10 | 11 | inscode = ( 12 | "0-???", "1 NOP", "0-???", "0-???", "0-???", "0-???", "1 TAP", "1 TPA", 13 | "1 INX", "1 DEX", "1 CLV", "1 SEV", "1 CLC", "1 SLC", "1 CLI", "1 SEI", 14 | 15 | "1 SBA", "1 CBA", "0-???", "0-???", "0-???", "0-???", "1 TAB", "1 TBA", 16 | "0-???", "1 DAA", "0-???", "1 ABA", "0-???", "0-???", "0-???", "0-???", 17 | 18 | "2rBRA", "0-???", "2rBHI", "2rBLS", "2rBCC", "2rBCS", "2rBNE", "2rBEQ", 19 | "2rBVC", "2rBVS", "2rBPL", "2rBMI", "2rBGE", "2rBLT", "2rBGT", "2rBLE", 20 | 21 | "1 TSX", "1 INS", "1 PULA","1 PULB","1 DES", "1 TXS", "1 PSHA","1 PSHB", 22 | "0-???", "1_RTS", "0-???", "1_RTI", "0-???", "0-???", "1 WAI", "1wSWI", 23 | 24 | 25 | "1 NEGA","0-???", "0-???", "1 COMA","1 LSRA","0-???", "1 RORA","1 ASLA", 26 | "1 ASLA","1 ROLA","1 DECA","0-???", "1 INCA","1 TSTA","0-???", "1 CLRA", 27 | 28 | "1 NEGB","0-???", "0-???", "1 COMB","1 LSRB","0-???", "1 RORB","1 ASRB", 29 | "1 ASLB","1 ROLB","1 DECB","0-???", "1 INCB","1 TSTB","0-???", "1 CLRB", 30 | 31 | "2xNEG", "0-???", "0-???", "2xCOM", "2xLSR", "0-???", "2xROR", "2xASR", 32 | "2xASL", "2xROL", "2xDEC", "0-???", "2xINC", "2xTST", "2XJMP", "2xCLR", 33 | 34 | "3eNEG", "0-???", "0-???", "3eCOM", "3eLSR", "0-???", "3eROR", "3eASR", 35 | "3eASL", "3eROL", "3eDEC", "0-???", "3eINC", "3eTST", "3jJMP", "3eCLR", 36 | 37 | 38 | "2iSUBA","2iCMPA","2iSBCA","0-???", "2iANDA","2iBITA","2iLDAA","0-???", 39 | "2iEORA","2iADCA","2iORAA","2iADDA","3iCPX", "2RBSR", "3iLDS", "0-???", 40 | 41 | "2dSUBA","2dCMPA","2dSBCA","0-???", "2dANDA","2dBITA","2dLDAA","2dSTAA", 42 | "2dEORA","2dADCA","2dORAA","2dADDA","2dCPX", "0-???", "2dLDS", "2dSTS", 43 | 44 | "2xSUBA","2xCMPA","2xSBCA","0-???", "2xANDA","2xBITA","2xLDAA","2xSTAA", 45 | "2xEORA","2xADCA","2xORAA","2xADDA","2xCPX", "2XJSR", "2xLDS", "2xSTS", 46 | 47 | "3eSUBA","3eCMPA","3eSBCA","0-???", "3eANDA","3eBITA","3eLDAA","3eSTAA", 48 | "3eEORA","3eADCA","3eORAA","3eADDA","3eCPX", "3sJSR", "3eLDS", "3eSTS", 49 | 50 | 51 | "2iSUBB","2iCMPB","2iSBCB","0-???", "2iANDB","2iBITB","2iLDAB","0-???", 52 | "2iEORB","2iADCB","2iORAB","2iADDB","0-???", "0-???", "3iLDX", "0-???", 53 | 54 | "2dSUBB","2dCMPB","2dSBCB","0-???", "2dANDB","2dBITB","2dLDAB","2dSTAB", 55 | "2dEORB","2dADCB","2dORAB","2dADDB","0-???", "0-???", "2dLDX", "2dSTX", 56 | 57 | "2xSUBB","2xCMPB","2xSBCB","0-???", "2xANDB","2xBITB","2xLDAB","2xSTAB", 58 | "2xEORB","2xADCB","2xORAB","2xADDB","0-???", "0-???", "2xLDX", "2xSTX", 59 | 60 | "3eSUBB","3eSTXB","3eSBCB","3eANDB","3eBITB","3eLDAB","3eLDAB","3eSTAB", 61 | "3eEORB","3eADCB","3eORAB","3eADDB","0-???", "0-???", "3eLDX", "3eSTX", 62 | ) 63 | 64 | class mc6800(disass.assy): 65 | """Motorola MC6800 Disassembler 66 | """ 67 | 68 | def __init__(self, p, name = "mc6800"): 69 | disass.assy.__init__(self, p, name) 70 | assert inscode[0x80] == "2iSUBA" 71 | assert inscode[0xc0] == "2iSUBB" 72 | assert len(inscode) == 256 73 | 74 | def do_disass(self, adr, ins): 75 | assert ins.lo == adr 76 | assert ins.status == "prospective" 77 | 78 | p = self.p 79 | 80 | iw = p.m.rd(adr) 81 | 82 | c = inscode[iw] 83 | l = int(c[0]) 84 | if l == 0: 85 | raise disass.DisassError("no instruction") 86 | 87 | ins.hi = adr + l 88 | if False: 89 | try: 90 | x = p.t.add(adr, adr + l, "ins") 91 | x.render = self.render 92 | except: 93 | print ("FAIL @ 0x%04x" % adr) 94 | return 95 | 96 | ins.mne = c[2:] 97 | 98 | if c[1] == "i" and l == 2: 99 | ins.oper = ("#0x%02x" % p.m.rd(adr + 1),) 100 | elif c[1] == "i" and l == 3: 101 | aa = p.m.b16(adr + 1) 102 | ins.oper = ("#0x%04x" % aa,) 103 | try: 104 | p.m.rd(aa) 105 | #XXX ins.ea = (aa,) 106 | except: 107 | pass 108 | elif c[1] == "x" and l == 2: 109 | ins.oper = ("0x%02x" % p.m.rd(adr + 1),"X") 110 | elif c[1] == "d": 111 | ins.oper = ("0x%02x" % p.m.rd(adr + 1),) 112 | #XXX ins.ea = (p.m.rd(adr + 1),) 113 | elif c[1] == "e": 114 | aa = p.m.b16(adr + 1) 115 | ins.oper = ("0x%04x" % aa,) 116 | #XXX ins.ea = (aa,) 117 | elif c[1] == "s": 118 | da = p.m.b16(adr + 1) 119 | ins.oper.append((da, "%s")) 120 | ins.flow("call", "T", da) 121 | elif c[1] == "R": 122 | da = adr + 2 + p.m.s8(adr + 1) 123 | ins.oper.append((da, "%s")) 124 | ins.flow("call", "T", da) 125 | elif c[1] == "r": 126 | da = adr + 2 + p.m.s8(adr + 1) 127 | ins.oper.append((da, "%s")) 128 | if iw & 0x0f == 00: 129 | ins.flow("cond", "T", da) 130 | else: 131 | c2 = inscode[iw ^ 1] 132 | ins.flow("cond", c2[3:], adr + l) 133 | ins.flow("cond", c[3:], da) 134 | elif c[1] == "j": 135 | da = p.m.b16(adr + 1) 136 | ins.oper.append((da, "%s")) 137 | ins.flow("cond", "T", da) 138 | elif c[1] == "X": 139 | ins.oper = ("0x%02x" % p.m.rd(adr + 1),"X") 140 | if ins.mne == "JSR": 141 | ins.flow("call", "T", None) 142 | else: 143 | ins.flow("cond", "T", None) 144 | elif c[1] == "_": 145 | if c[2:] == "RTI": 146 | ins.flow("ret", "IRQ", None) 147 | else: 148 | ins.flow("ret", "T", None) 149 | elif c[1] == "w": 150 | ins.flow("call.SWI", "T", None) 151 | elif c[1] == " ": 152 | pass 153 | else: 154 | print("UNIMPL %04x: %02x %s" % (adr,iw, c)) 155 | raise disass.DisassError("bug", c) 156 | 157 | def __vector(self, adr, nm): 158 | x = const.ptr(self.p, adr, 2) 159 | x.cmt.append("Vector: " + nm) 160 | w = self.p.m.w16(adr) 161 | x.a['flow'] = (("cond", "T", w),) 162 | self.disass(w) 163 | self.p.setlabel(w, nm + "_VECTOR") 164 | 165 | def vectors(self, adr = 0x10000): 166 | """Instantiate the four MC6800 vectors 167 | 168 | adr: 169 | Address mapped to top of memory 170 | """ 171 | 172 | self.__vector(adr - 2, "RST") 173 | self.__vector(adr - 4, "NMI") 174 | self.__vector(adr - 6, "SWI") 175 | self.__vector(adr - 8, "IRQ") 176 | x = self.p.t.add(adr - 8, adr, "tbl") 177 | x.blockcmt += "\n-\nMC6800 Vector Table\n\n" 178 | -------------------------------------------------------------------------------- /cpus/mcs4.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Intel MCS 48 family disassembler 4 | # 5 | 6 | import instree 7 | import disass 8 | 9 | import pseudo 10 | 11 | ####################################################################### 12 | 13 | class mcs4(disass.assy): 14 | 15 | def __init__(self, p, name = "mcs48"): 16 | disass.assy.__init__(self, p, name) 17 | self.root = instree.instree( 18 | width = 8, 19 | filename = __file__[:-3] + "_instructions.txt" 20 | ) 21 | 22 | def do_disass(self, adr, ins): 23 | assert ins.lo == adr 24 | assert ins.status == "prospective" 25 | 26 | p = self.p 27 | 28 | # By default... 29 | ins.hi = ins.lo + 1 30 | 31 | c = self.root.find(p, adr, p.m.rd) 32 | assert c != None 33 | #print(">>>> %03x" % adr, "%02x" % p.m.rd(adr), c, "wid",c.width) 34 | ins.hi = ins.lo + (c.width >> 3) 35 | ins.mne = c.spec[0] 36 | ins.oper = list() 37 | for i in c.spec[1].split(","): 38 | if i == "-": 39 | pass 40 | elif i == "ladr": 41 | hi = c.get_field(p, adr, p.m.rd, 1, "ahi") 42 | lo = c.get_field(p, adr, p.m.rd, 1, "alo") 43 | da = (hi << 8) | lo 44 | ins.oper.append((da, "%s", "0x%03x" % da)) 45 | elif i == "adr": 46 | hi = adr >> 8 47 | lo = c.get_field(p, adr, p.m.rd, 1, i) 48 | da = (hi << 8) | lo 49 | ins.oper.append((da, "%s", "0x%03x" % da)) 50 | elif i == "rr": 51 | reg8 = c.get_field(p, adr, p.m.rd, 1, i) 52 | reg8 <<= 1 53 | ins.oper.append("rr%d" % reg8) 54 | elif i == "r": 55 | reg = c.get_field(p, adr, p.m.rd, 1, i) 56 | ins.oper.append("r%d" % reg) 57 | elif i == "data": 58 | d8 = c.get_field(p, adr, p.m.rd, 1, i) 59 | ins.oper.append("#0x%02x" % d8) 60 | elif i == "d": 61 | d4 = c.get_field(p, adr, p.m.rd, 1, i) 62 | ins.oper.append("#0x%01x" % d4) 63 | elif i == "cc": 64 | x = c.get_field(p, adr, p.m.rd, 1, i) 65 | if x == 1: 66 | cc = "JNT" 67 | elif x == 2: 68 | cc = "JC" 69 | elif x == 4: 70 | cc = "JZ" 71 | elif x == 9: 72 | cc = "JT" 73 | elif x == 10: 74 | cc = "JNC" 75 | elif x == 12: 76 | cc = "JNZ" 77 | else: 78 | cc = "CC#%01x" % x 79 | ins.oper.append(cc) 80 | elif i == "(rr0)": 81 | ins.oper.append(i) 82 | else: 83 | print("MISS", i, c) 84 | ins.oper.append(i) 85 | if ins.mne == "JCN": 86 | ins.flow("cond", "!" + cc, ins.hi) 87 | ins.flow("cond", cc, da) 88 | elif ins.mne == "ISZ": 89 | ins.flow("cond", "Z", ins.hi) 90 | ins.flow("cond", "NZ", da) 91 | elif ins.mne == "JUN": 92 | ins.flow("cond", "T", da) 93 | elif ins.mne == "JMS": 94 | ins.flow("call", "T", da) 95 | elif ins.mne == "BBL": 96 | ins.flow("ret", "T", None) 97 | 98 | ############# 99 | # PSEUDO CODE 100 | 101 | if ins.mne == "ADD": 102 | ins.pseudo = ( 103 | pseudo.add(("ra", ins.oper[0]), "tmp0"), 104 | pseudo.add(("tmp0", "rc"), "tmp1"), 105 | pseudo.mov(("tmp1",), "ra"), 106 | pseudo.rsh(("tmp1", 4), "rc"), 107 | ) 108 | elif ins.mne == "ADM": 109 | ins.pseudo = ( 110 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 111 | pseudo.ldm(("tmp0", "RAM"), "tmp1"), 112 | pseudo.add(("tmp1", "ra"), "tmp0"), 113 | pseudo.add(("tmp0", "rc"), "tmp1"), 114 | pseudo.mov(("tmp1",), "ra"), 115 | pseudo.rsh(("tmp1", 4), "rc"), 116 | ) 117 | elif ins.mne == "BBL": 118 | ins.pseudo = ( 119 | pseudo.mov((d4,), "ra"), 120 | pseudo.ret((), None), 121 | ) 122 | elif ins.mne == "CLB": 123 | ins.pseudo = ( 124 | pseudo.mov((0,), "ra"), 125 | pseudo.mov((0,), "rc"), 126 | ) 127 | elif ins.mne == "CLC": 128 | ins.pseudo = ( 129 | pseudo.mov((0,), "rc"), 130 | ) 131 | elif ins.mne == "CMA": 132 | ins.pseudo = ( 133 | pseudo.xor(("ra", 0xf), "tmp0"), 134 | pseudo.mov(("tmp0",), "ra"), 135 | ) 136 | elif ins.mne == "CMC": 137 | ins.pseudo = ( 138 | pseudo.xor((0x1, "rc"), "tmp0"), 139 | pseudo.mov(("tmp0",), "rc"), 140 | ) 141 | elif ins.mne == "DAA": 142 | ins.pseudo = ( 143 | pseudo.xxx(("ra", "rc"), "tmp0"), 144 | # ("mcs4::daa", ("ra", "rc"), "tmp0"), 145 | pseudo.mov(("tmp0",), "ra"), 146 | pseudo.rsh(("tmp0", 4), "rc"), 147 | ) 148 | elif ins.mne == "DAC": 149 | ins.pseudo = ( 150 | pseudo.add(("ra", 0xf), "tmp0"), 151 | pseudo.mov(("tmp0",), "ra"), 152 | pseudo.rsh(("tmp0", 4), "rc"), 153 | ) 154 | elif ins.mne == "DCL": 155 | ins.pseudo = ( 156 | pseudo.lsh(("ra", 8), "rdcl"), 157 | ) 158 | elif ins.mne == "FIN": 159 | ins.pseudo = ( 160 | pseudo.lor((ins.hi & 0xf00, "r1"), "tmp0"), 161 | pseudo.lsh(("r0", 4), "tmp1"), 162 | pseudo.lor(("tmp1", "tmp0"), "tmp2"), 163 | pseudo.ldm(("tmp2", "ROM"), "tmp1"), 164 | pseudo.mov(("tmp1",), "r%d" % (reg8 + 1)), 165 | pseudo.rsh(("tmp1", 4), "r%d" % reg8), 166 | ) 167 | elif ins.mne == "FIM": 168 | ins.pseudo = ( 169 | pseudo.mov((d8>>4,), "r%d" % reg8), 170 | pseudo.mov((d8 & 0xf,), "r%d" % (reg8+1)), 171 | ) 172 | elif ins.mne == "IAC": 173 | ins.pseudo = ( 174 | pseudo.add(("ra", 1), "tmp0"), 175 | pseudo.mov(("tmp0",), "ra"), 176 | pseudo.rsh(("tmp0", 4), "rc"), 177 | ) 178 | elif ins.mne == "INC": 179 | ins.pseudo = ( 180 | pseudo.add((1, ins.oper[0]), "tmp0"), 181 | pseudo.mov(("tmp0",), ins.oper[0]), 182 | ) 183 | elif ins.mne == "ISZ": 184 | ins.pseudo = ( 185 | pseudo.add((1, ins.oper[0]), "tmp0"), 186 | pseudo.mov(("tmp0",), ins.oper[0]), 187 | pseudo.xxx(), 188 | ) 189 | elif ins.mne == "JCN": 190 | ins.pseudo = ( 191 | pseudo.xxx(), 192 | ) 193 | elif ins.mne == "JIN": 194 | ins.pseudo = ( 195 | pseudo.xxx(), 196 | ) 197 | elif ins.mne == "JMS": 198 | ins.pseudo = ( 199 | pseudo.xxx(), 200 | ) 201 | elif ins.mne == "JUN": 202 | ins.pseudo = ( 203 | pseudo.xxx(), 204 | ) 205 | elif ins.mne == "KBP": 206 | ins.pseudo = ( 207 | pseudo.xxx(("ra",), "tmp0"), 208 | # ("mcs4::kbp", ("ra",), "tmp0"), 209 | pseudo.mov(("tmp0",), "ra"), 210 | ) 211 | elif ins.mne == "LD": 212 | ins.pseudo = ( 213 | pseudo.mov((ins.oper[0],), "ra"), 214 | ) 215 | elif ins.mne == "LDM": 216 | ins.pseudo = ( 217 | pseudo.mov((d4,), "ra"), 218 | ) 219 | elif ins.mne == "NOP": 220 | ins.pseudo = ( 221 | pseudo.nop(), 222 | ) 223 | elif ins.mne == "RAL": 224 | ins.pseudo = ( 225 | pseudo.lsh(("ra", 1), "tmp0"), 226 | pseudo.lor(("tmp0", "rc"), "tmp1"), 227 | pseudo.mov(("tmp1",), "ra"), 228 | pseudo.rsh(("tmp1", 4), "rc"), 229 | ) 230 | elif ins.mne == "RAR": 231 | ins.pseudo = ( 232 | pseudo.lsh(("rc", 3), "tmp0"), 233 | pseudo.mov(("ra",), "rc"), 234 | pseudo.rsh(("ra", 1), "tmp1"), 235 | pseudo.lor(("tmp0", "tmp1"), "ra"), 236 | ) 237 | elif ins.mne in ("RD0", "RD1", "RD2", "RD3"): 238 | ins.pseudo = ( 239 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 240 | pseudo.land(("tmp0", 0x7f0), "tmp1"), 241 | pseudo.ldm(("tmp1", int(ins.mne[-1]), 242 | "RAMSTATUS"), "ra"), 243 | ) 244 | elif ins.mne == "RDM": 245 | ins.pseudo = ( 246 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 247 | pseudo.ldm(("tmp0", "RAM"), "ra"), 248 | ) 249 | elif ins.mne == "RDR": 250 | ins.pseudo = ( 251 | pseudo.land(("rsrc", 0xf0), "tmp0"), 252 | pseudo.ldm(("tmp0", "ROMPORT"), "ra"), 253 | ) 254 | elif ins.mne == "SBM": 255 | ins.pseudo = ( 256 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 257 | pseudo.ldm(("tmp0", "RAM"), "tmp1"), 258 | pseudo.xor(("tmp1", 0xf), "tmp0"), 259 | pseudo.add(("tmp0", "ra"), "tmp1"), 260 | pseudo.xor(("rc", 0x1), "tmp0"), 261 | pseudo.add(("tmp0", "tmp1"), "tmp2"), 262 | pseudo.mov(("tmp2",), "ra"), 263 | pseudo.rsh(("tmp2", 4), "rc"), 264 | ) 265 | elif ins.mne == "SRC": 266 | ins.pseudo = ( 267 | pseudo.lsh(("r%d" % reg8, 4), "tmp0"), 268 | pseudo.lor(("r%d" % (reg8+1), "tmp0"), "rsrc"), 269 | ) 270 | elif ins.mne == "STC": 271 | ins.pseudo = ( 272 | pseudo.mov((1,), "tc"), 273 | ) 274 | elif ins.mne == "SUB": 275 | ins.pseudo = ( 276 | pseudo.xor((ins.oper[0], 0xf), "tmp0"), 277 | pseudo.add(("tmp0", "ra"), "tmp1"), 278 | pseudo.xor(("rc", 1), "tmp0"), 279 | pseudo.add(("tmp0", "tmp1"), "tmp2"), 280 | pseudo.mov(("tmp2",), "ra"), 281 | pseudo.rsh(("tmp2", 4), "rc"), 282 | ) 283 | elif ins.mne == "TCC": 284 | ins.pseudo = ( 285 | pseudo.mov(("rc",), "ra"), 286 | pseudo.mov((0,), "rc"), 287 | ) 288 | elif ins.mne == "TCS": 289 | ins.pseudo = ( 290 | pseudo.add(("rc", 9), "ra"), 291 | pseudo.mov((0,), "rc"), 292 | ) 293 | elif ins.mne == "WMP": 294 | ins.pseudo = ( 295 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 296 | pseudo.land(("tmp0", 0x7c0), "tmp1"), 297 | pseudo.stm(("ra", "tmp1", "RAMPORT"), True), 298 | ) 299 | elif ins.mne in ("WR0", "WR1", "WR2", "WR3"): 300 | ins.pseudo = ( 301 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 302 | pseudo.land(("tmp0", 0x7f0), "tmp1"), 303 | pseudo.stm(("ra", "tmp1", int(ins.mne[-1]), 304 | "RAMSTATUS"), True), 305 | ) 306 | elif ins.mne == "WRM": 307 | ins.pseudo = ( 308 | pseudo.lor(("rdcl", "rsrc"), "tmp0"), 309 | pseudo.stm(("ra", "tmp0", "RAM"), True), 310 | ) 311 | elif ins.mne == "WRR": 312 | ins.pseudo = ( 313 | pseudo.land(("rsrc", 0xf0), "tmp0"), 314 | pseudo.stm(("ra", "tmp0", "ROMPORT"), True), 315 | ) 316 | elif ins.mne == "XCH": 317 | ins.pseudo = ( 318 | pseudo.mov(("ra",), "tmp0"), 319 | pseudo.mov((ins.oper[0],), "ra"), 320 | pseudo.mov(("tmp0",), ins.oper[0]), 321 | ) 322 | else: 323 | print("XXX: Missing pseudo", ins.mne) 324 | if False: 325 | for i in ins.pseudo: 326 | for j in i[1]: 327 | if type(j) == str and i[2] == j: 328 | print("XXX", i, ins.mne, ins.oper) 329 | 330 | -------------------------------------------------------------------------------- /cpus/mcs48.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Intel MCS 48 family disassembler 4 | # 5 | 6 | import instree 7 | import disass 8 | 9 | ####################################################################### 10 | 11 | class mcs48(disass.assy): 12 | 13 | def __init__(self, p, name = "mcs48"): 14 | disass.assy.__init__(self, p, name) 15 | self.root = instree.instree( 16 | width = 8, 17 | filename = __file__[:-3] + "_instructions.txt" 18 | ) 19 | 20 | def do_disass(self, adr, ins): 21 | assert ins.lo == adr 22 | assert ins.status == "prospective" 23 | 24 | p = self.p 25 | 26 | # By default... 27 | ins.hi = ins.lo + 1 28 | 29 | #print(">>> @%04x" % adr, "%02x" % p.m.rd(adr)) 30 | c = self.root.find(p, adr, p.m.rd) 31 | assert c != None 32 | #print(">>>> ", c, "wid",c.width) 33 | ins.hi = ins.lo + (c.width >> 3) 34 | ins.mne = c.spec[0] 35 | ins.oper = list() 36 | for i in c.spec[1].split(","): 37 | if i == "laddr": 38 | hi = c.get_field(p, adr, p.m.rd, 1, "ahi") 39 | lo = c.get_field(p, adr, p.m.rd, 1, "alow") 40 | da = (hi << 8) | lo 41 | ins.oper.append((da, "%s", "0x%03x" % da)) 42 | elif i == "addr": 43 | j = c.get_field(p, adr, p.m.rd, 1, i) 44 | da = adr & ~0xff 45 | da |= j 46 | ins.oper.append((da, "%s", "0x%03x" % da)) 47 | elif i == "@A": 48 | ins.oper.append(i) 49 | da = None 50 | elif i == "@Rr": 51 | j = c.get_field(p, adr, p.m.rd, 1, "r") 52 | ins.oper.append("@R%d" % j) 53 | elif i == "Rr": 54 | j = c.get_field(p, adr, p.m.rd, 1, i) 55 | ins.oper.append("R%d" % j) 56 | elif i == "Pp": 57 | j = c.get_field(p, adr, p.m.rd, 1, i) 58 | ins.oper.append("P%d" % j) 59 | elif i == "data": 60 | j = c.get_field(p, adr, p.m.rd, 1, i) 61 | ins.oper.append("#0x%02x" % j) 62 | 63 | elif i == "b": 64 | j = c.get_field(p, adr, p.m.rd, 1, i) 65 | ins.mne = "JP%d" % j 66 | elif i in ("T", "PSW", "F1", "F0", "TCNT", "BUS", 67 | "A", "C", "RB1", "RB0", "TCNTI", "I", "CLK", 68 | "MB0", "MB1"): 69 | ins.oper.append(i) 70 | elif i == "-": 71 | pass 72 | else: 73 | print("MISS", i, c) 74 | ins.oper.append(i) 75 | if ins.mne == "JMP": 76 | ins.flow("cond", "T", da) 77 | elif ins.mne == "JMPP": 78 | ins.flow("cond", "?", None) 79 | elif ins.mne == "CALL": 80 | ins.flow("call", "T", da) 81 | elif ins.mne[0] == "J": 82 | ins.flow("cond", ins.mne[1:], da) 83 | ins.flow("cond", "N" + ins.mne[1:], ins.hi) 84 | elif ins.mne == "DJNZ": 85 | ins.flow("cond", "NZ", da) 86 | ins.flow("cond", "Z", ins.hi) 87 | elif ins.mne == "RET": 88 | ins.flow("ret", "T", None) 89 | elif ins.mne == "RETR": 90 | ins.flow("ret", "T", None) 91 | 92 | -------------------------------------------------------------------------------- /cpus/mcs48_instructions.txt: -------------------------------------------------------------------------------- 1 | # MCS48 CPU instructions 2 | 3 | ADD A,Rr |0 1 1 0|1| Rr | 4 | ADD A,@Rr |0 1 1 0|0 0 0|r| 5 | ADD A,data |0 0 0 0|0 0 1 1| data | 6 | 7 | ADDC A,Rr |0 1 1 1|1| Rr | 8 | ADDC A,@Rr |0 1 1 1|0 0 0|r| 9 | ADDC A,data |0 0 0 1|0 0 1 1| data | 10 | 11 | ANL A,Rr |0 1 0 1|1| Rr | 12 | ANL A,@Rr |0 1 0 1|0 0 0|r| 13 | ANL A,data |0 1 0 1|0 0 1 1| data | 14 | 15 | ANL BUS,data |1 0 0 1|1 0 0 0| data | 16 | ANL Pp,data |1 0 0 1|1 0|Pp | data | 17 | 18 | ANLD Pp,A |1 0 0 1|1 1|Pp | data | 19 | 20 | CALL laddr | ahi |1|0 1 0 0| alow | 21 | 22 | CLR A |0 0 1 0|0 1 1 1| 23 | CLR C |1 0 0 1|0 1 1 1| 24 | CLR F0 |1 0 0 0|0 1 0 1| 25 | CLR F1 |1 0 1 0|0 1 0 1| 26 | CPL A |0 0 1 1|0 1 1 1| 27 | CPL C |1 0 1 0|0 1 1 1| 28 | CPL F0 |1 0 0 1|0 1 0 1| 29 | CPL F1 |1 0 1 1|0 1 0 1| 30 | 31 | DA A |0 1 0 1|0 1 1 1| 32 | 33 | DEC A |0 0 0 0|0 1 1 1| 34 | DEC Rr |1 1 0 0|1| Rr | 35 | DIS I |0 0 0 1|0 1 0 1| 36 | DIS TCNTI |0 0 1 1|0 1 0 1| 37 | 38 | DJNZ Rr,addr |1 1 1 0|1| Rr | addr | 39 | 40 | EN I |0 0 0 0|0 1 0 1| 41 | EN TCNTI |0 0 1 0|0 1 0 1| 42 | 43 | ENT0 CLK |0 1 1 1|0 1 0 1| 44 | IN A,Pp |0 0 0 0|1 0|Pp | 45 | INC A |0 0 0 1|0 1 1 1| 46 | INC Rr |0 0 0 1|1| Rr | 47 | INC @Rr |0 0 0 1|0 0 0|r| 48 | 49 | IN A,BUS |0 0 0 0|1 0 0 0| 50 | JB b,addr |b |1|0 0 1 0| addr | 51 | JC addr |1 1 1 1|0 1 1 0| addr | 52 | JF0 addr |1 0 1 1|0 1 1 0| addr | 53 | JF1 addr |0 1 1 1|0 1 1 0| addr | 54 | JMP laddr | ahi |0|0 1 0 0| alow | 55 | JMPP @A |1 0 1 1|0 0 1 1| 56 | JNC addr |1 1 1 0|0 1 1 0| addr | 57 | JNI addr |1 0 0 0|0 1 1 0| addr | 58 | JNT0 addr |0 0 1 0|0 1 1 0| addr | 59 | JNT1 addr |0 1 0 0|0 1 1 0| addr | 60 | 61 | JNZ addr |1 0 0 1|0 1 1 0| addr | 62 | JTF addr |0 0 0 1|0 1 1 0| addr | 63 | JT0 addr |0 0 1 1|0 1 1 0| addr | 64 | JT1 addr |0 1 0 1|0 1 1 0| addr | 65 | JZ addr |1 1 0 0|0 1 1 0| addr | 66 | 67 | MOV A,data |0 0 1 0|0 0 1 1| data | 68 | MOV A,PSW |1 1 0 0|0 1 1 1| 69 | MOV A,Rr |1 1 1 1|1| Rr | 70 | MOV A,@Rr |1 1 1 1|0 0 0|r| 71 | MOV A,T |0 1 0 0|0 0 1 0| 72 | MOV PSW,A |1 1 0 1|0 1 1 1| 73 | MOV Rr,A |1 0 1 0|1| Rr | 74 | MOV Rr,data |1 0 1 1|1| Rr | data | 75 | MOV @Rr,A |1 0 1 0|0 0 0|r| 76 | MOV @Rr,data |1 0 1 1|0 0 0|r| data | 77 | MOV T,A |0 1 1 0|0 0 1 0| 78 | MOVD A,Pp |0 0 0 0|1 1| Pp| 79 | MOVD Pp,A |0 0 1 1|1 1| Pp| 80 | MOVP A,@A |1 0 1 0|0 0 1 1| 81 | MOVP3 A,@A |1 1 1 0|0 0 1 1| 82 | MOVX A,@Rr |1 0 0 0|0 0 0|r| 83 | MOVX @Rr,A |1 0 0 1|0 0 0|r| 84 | NOP - |0 0 0 0|0 0 0 0| 85 | ORL A,Rr |0 1 0 0|1| Rr | 86 | ORL A,@Rr |0 1 0 0|0 0 0|r| 87 | ORL A,data |0 1 0 0|0 0 1 1| data | 88 | ORL BUS,data |1 0 0 0|1 0 0 0| data | 89 | ORL Pp,data |1 0 0 0|1 0| Pp| data | 90 | 91 | ORLD Pp,A |1 0 0 0|1 1| Pp| 92 | OUTL BUS,A |0 0 0 0|0 0 1 0| 93 | OUTL Pp,A |0 0 1 1|1 0| Pp| 94 | 95 | RET - |1 0 0 0|0 0 1 1| 96 | RETR - |1 0 0 1|0 0 1 1| 97 | 98 | RL A |1 1 1 0|0 1 1 1| 99 | RLC A |1 1 1 1|0 1 1 1| 100 | RR A |0 1 1 1|0 1 1 1| 101 | RRC A |0 1 1 0|0 1 1 1| 102 | 103 | STOP TCNT |0 1 1 0|0 1 0 1| 104 | STRT TCNT |0 1 0 0|0 1 0 1| 105 | STRT T |0 1 0 1|0 1 0 1| 106 | SWAP A |0 1 0 0|0 1 1 1| 107 | XCH A,Rr |0 0 1 0|1| Rr | 108 | XCH A,@Rr |0 0 1 0|0 0 0|r| 109 | XCHD A,@Rr |0 0 1 1|0 0 0|r| 110 | XRL A,Rr |1 1 0 1|1| Rr | 111 | XRL A,@Rr |1 1 0 1|0 0 0|r| 112 | XRL A,data |1 1 0 1|0 0 1 1| data | 113 | 114 | SEL MB0 |1 1 1 0|0 1 0 1| 115 | SEL MB1 |1 1 1 1|0 1 0 1| 116 | SEL RB0 |1 1 0 0|0 1 0 1| 117 | SEL RB1 |1 1 0 1|0 1 0 1| 118 | -------------------------------------------------------------------------------- /cpus/mcs4_instructions.txt: -------------------------------------------------------------------------------- 1 | # MCS4 CPU instructions 2 | 3 | NOP - |0 0 0 0|0 0 0 0| 4 | JCN cc,adr |0 0 0 1| cc | adr | 5 | FIM rr,data |0 0 1 0| rr |0| data | 6 | SRC rr |0 0 1 0| rr |1| 7 | FIN rr,(rr0) |0 0 1 1| rr |0| 8 | JIN rr |0 0 1 1| rr |1| 9 | JUN ladr |0 1 0 0| ahi | alo | 10 | JMS ladr |0 1 0 1| ahi | alo | 11 | INC r |0 1 1 0| r | 12 | ISZ r,adr |0 1 1 1| r | adr | 13 | ADD r |1 0 0 0| r | 14 | SUB r |1 0 0 1| r | 15 | LD r |1 0 1 0| r | 16 | XCH r |1 0 1 1| r | 17 | BBL d |1 1 0 0| d | 18 | LDM d |1 1 0 1| d | 19 | WRM - |1 1 1 0|0 0 0 0| 20 | WMP - |1 1 1 0|0 0 0 1| 21 | WRR - |1 1 1 0|0 0 1 0| 22 | WPM - |1 1 1 0|0 0 1 1| 23 | WR0 - |1 1 1 0|0 1 0 0| 24 | WR1 - |1 1 1 0|0 1 0 1| 25 | WR2 - |1 1 1 0|0 1 1 0| 26 | WR3 - |1 1 1 0|0 1 1 1| 27 | SBM - |1 1 1 0|1 0 0 0| 28 | RDM - |1 1 1 0|1 0 0 1| 29 | RDR - |1 1 1 0|1 0 1 0| 30 | ADM - |1 1 1 0|1 0 1 1| 31 | RD0 - |1 1 1 0|1 1 0 0| 32 | RD1 - |1 1 1 0|1 1 0 1| 33 | RD2 - |1 1 1 0|1 1 1 0| 34 | RD3 - |1 1 1 0|1 1 1 1| 35 | CLB - |1 1 1 1|0 0 0 0| 36 | CLC - |1 1 1 1|0 0 0 1| 37 | IAC - |1 1 1 1|0 0 1 0| 38 | CMC - |1 1 1 1|0 0 1 1| 39 | CMA - |1 1 1 1|0 1 0 0| 40 | RAL - |1 1 1 1|0 1 0 1| 41 | RAR - |1 1 1 1|0 1 1 0| 42 | TCC - |1 1 1 1|0 1 1 1| 43 | DAC - |1 1 1 1|1 0 0 0| 44 | TCS - |1 1 1 1|1 0 0 1| 45 | STC - |1 1 1 1|1 0 1 0| 46 | DAA - |1 1 1 1|1 0 1 1| 47 | KBP - |1 1 1 1|1 1 0 0| 48 | DCL - |1 1 1 1|1 1 0 1| 49 | 50 | -------------------------------------------------------------------------------- /cpus/mcs51.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Intel MCS 51 family disassembler 4 | # 5 | 6 | import instree 7 | import disass 8 | 9 | ####################################################################### 10 | 11 | class mcs51(disass.assy): 12 | 13 | def __init__(self, p, name = "mcs51"): 14 | disass.assy.__init__(self, p, name) 15 | self.root = instree.instree( 16 | width = 8, 17 | filename = __file__[:-3] + "_instructions.txt" 18 | ) 19 | 20 | def do_disass(self, adr, ins): 21 | assert ins.lo == adr 22 | assert ins.status == "prospective" 23 | 24 | p = self.p 25 | 26 | # By default... 27 | ins.hi = ins.lo + 1 28 | 29 | print(">>> @%04x" % adr, "%02x" % p.m.rd(adr)) 30 | c = self.root.find(p, adr, p.m.rd) 31 | assert c != None 32 | print(">>>> ", c, "wid",c.width) 33 | ins.hi = ins.lo + (c.width >> 3) 34 | ins.mne = c.spec[0] 35 | ins.oper = list() 36 | for i in c.spec[1].split(","): 37 | if i == "a16": 38 | hi = c.get_field(p, adr, p.m.rd, 1, "ahi") 39 | lo = c.get_field(p, adr, p.m.rd, 1, "alo") 40 | da = (hi << 8) | lo 41 | ins.oper.append((da, "%s", "0x%03x" % da)) 42 | elif i == "addr11": 43 | hi = c.get_field(p, adr, p.m.rd, 1, "ahi") 44 | lo = c.get_field(p, adr, p.m.rd, 1, "alo") 45 | da = (hi << 8) | lo 46 | da |= ins.hi & 0xf800 47 | ins.oper.append((da, "%s", "0x%03x" % da)) 48 | elif i == "arel": 49 | rel = c.get_field(p, adr, p.m.rd, 1, i) 50 | if rel & 0x80: 51 | rel -= 256 52 | da = ins.hi + rel 53 | ins.oper.append((da, "%s", "0x%03x" % da)) 54 | elif i in ("A", "DPTR"): 55 | ins.oper.append(i) 56 | continue 57 | elif i == "-": 58 | continue 59 | else: 60 | ins.oper.append("??" + i) 61 | print("???", i) 62 | if ins.mne in ("LJMP", "SJMP", "AJMP"): 63 | ins.flow("cond", "T", da) 64 | elif ins.mne in ("JB", "JNB", "JBC", "JC", "JNC", "JZ", "JNZ", 65 | "DJNZ", "CJNE"): 66 | ins.flow("cond", ins.mne[1:], da) 67 | ins.flow("cond", "!" + ins.mne[1:], ins.hi) 68 | elif ins.mne == "LCALL" or ins.mne == "ACALL": 69 | ins.flow("call", "T", da) 70 | elif ins.mne == "RET": 71 | ins.flow("ret", "T", None) 72 | elif ins.mne == "RETI": 73 | ins.flow("ret", "I", None) 74 | return 75 | -------------------------------------------------------------------------------- /cpus/mcs51_instructions.txt: -------------------------------------------------------------------------------- 1 | # MCS51 Instructions 2 | 3 | # |. . . . . . . .|. . . . . . . .| 4 | ACALL addr11 | ahi |1 0 0 0 1| alo | 5 | 6 | ADD A,Rn |0 0 1 0 1| rn | 7 | ADD A,adir |0 0 1 0 0 1 0 1| adir | 8 | ADD A,@Ri |0 0 1 0 0 1 1|i| 9 | ADD A,#data |0 0 1 0 0 1 0 0| data | 10 | 11 | ADC A,Rn |0 0 1 1 1| rn | 12 | ADC A,adir |0 0 1 1 0 1 0 1| adir | 13 | ADC A,@Ri |0 0 1 1 0 1 1|i| 14 | ADC A,imm |0 0 1 1 0 1 0 0| imm | 15 | 16 | AJMP addr11 | ahi |0 0 0 0 1| alo | 17 | 18 | ANL A,Rn |0 1 0 1 1| rn | 19 | ANL A,adir |0 1 0 1 0 1 0 1| adir | 20 | ANL A,@Ri |0 1 0 1 0 1 1|i| 21 | ANL A,#data |0 1 0 1 0 1 0 0| data | 22 | 23 | ANL adir,A |0 1 0 1 0 0 1 0| adir | 24 | ANL adir,#data |0 1 0 1 0 0 1 1| adir | data | 25 | ANL C,bit |1 0 0 0 0 0 1 0| abit | 26 | ANL C,/bit |1 0 1 1 0 0 0 0| abit | 27 | 28 | CJNE A,adir,arel |1 0 1 1 0 1 0 1| adir | arel | 29 | CJNE A,#data,arel |1 0 1 1 0 1 0 0| data | arel | 30 | CJNE Rn,#data,arel |1 0 1 1 1| rn | data | arel | 31 | CJNE @Ri,#data,arel |1 0 1 1 0 1 1|i| data | arel | 32 | 33 | CLR A |1 1 1 0 0 1 0 0| 34 | CLR C |1 1 0 0 0 0 1 1| 35 | CLR bit |1 1 0 0 0 0 1 0| abit | 36 | 37 | CPL A |1 1 1 1 0 1 0 0| 38 | CPL C |1 0 1 1 0 0 1 1| 39 | CPL bit |1 0 1 1 0 0 1 0| abit | 40 | 41 | DA A |1 1 0 1 0 1 0 0| 42 | 43 | DEC A |0 0 0 1 0 1 0 0| 44 | DEC Rn |0 0 0 1 1| rn | 45 | DEC adir |0 0 0 1 0 1 0 1| adir | 46 | DEC @Ri |0 0 0 1 0 1 1|i| 47 | 48 | DIV AB |1 0 0 0 0 1 0 0| 49 | 50 | DJNZ Rn,arel |1 1 0 1 1| rn | arel | 51 | DJNZ adir,arel |1 1 0 1 0 1 0 1| adir | arel | 52 | 53 | INC A |0 0 0 0 0 1 0 0| 54 | INC Rn |0 0 0 0 1| rn | 55 | INC adir |0 0 0 0 0 1 0 1| adir | 56 | INC @Ri |0 0 0 0 0 1 1|i| 57 | INC DPTR |1 0 1 0 0 0 1 1| 58 | 59 | JB abit,arel |0 0 1 0 0 0 0 0| abit | arel | 60 | JBC abit,arel |0 0 0 1 0 0 0 0| abit | arel | 61 | 62 | JC arel |0 1 0 0 0 0 0 0| arel | 63 | 64 | JMP @A+DPTR |0 1 1 1 0 0 1 1| 65 | 66 | JNB abit,arel |0 0 1 1 0 0 0 0| abit | arel | 67 | 68 | JNC arel |0 1 0 1 0 0 0 0| arel | 69 | 70 | JNZ arel |0 1 1 1 0 0 0 0| arel | 71 | 72 | JZ arel |0 1 1 0 0 0 0 0| arel | 73 | 74 | LCALL a16 |0 0 0 1 0 0 1 0| ahi | alo | 75 | 76 | LJMP a16 |0 0 0 0 0 0 1 0| ahi | alo | 77 | 78 | MOV A,Rn |1 1 1 0 1| rn | 79 | MOV A,adir |1 1 1 0 0 1 0 1| adir | 80 | MOV A,@Ri |1 1 1 0 0 1 1|i| 81 | MOV A,#data |0 1 1 1 0 1 0 0| data | 82 | MOV Rn,A |1 1 1 1 1| rn | 83 | MOV Rn,adir |1 0 1 0 1| rn | adir | 84 | MOV Rn,#data |0 1 1 1 1| rn | data | 85 | MOV adir,A |1 1 1 1 0 1 0 1| adir | 86 | MOV adir,Rn |1 0 0 0 1| rn | adir | 87 | MOV adir,adir2 |1 0 0 0 0 1 0 | adir | adir2 | 88 | MOV adir,@Ri |1 0 0 0 0 1 1|i| adir | 89 | MOV adir,#data |0 1 1 1 0 1 0 1| adir | data | 90 | MOV @Ri,A |1 1 1 1 0 1 1|i| 91 | MOV @Ri,adir |1 0 1 0 0 1 1|i| adir | 92 | MOV @Ri,#data |0 1 1 1 0 1 1|i| data | 93 | 94 | MOV C,bit |1 0 1 0 0 0 1 0| bit | 95 | MOV bit,C |1 0 0 1 0 0 1 0| bit | 96 | 97 | MOV DPTR,#data16 |1 0 0 1 0 0 0 0| dhi | dlo | 98 | 99 | MOVC A,@A+DPTR |1 0 0 1 0 0 1 1| 100 | MOVC A,@A+PC |1 0 0 0 0 0 1 1| 101 | 102 | MOVX A,@Ri |1 1 1 0 0 0 1|i| 103 | MOVX A,@DPTR |1 1 1 0 0 0 0 0| 104 | MOVX @Ri,A |1 1 1 1 0 0 1|i| 105 | MOVX @DPTR,A |1 1 1 1 0 0 0 0| 106 | 107 | MUL AB |1 0 1 0 0 1 0 0| 108 | 109 | NOP - |0 0 0 0 0 0 0 0| 110 | 111 | ORL A,Rn |0 1 0 0 1| rn | 112 | ORL A,adir |0 1 0 0 0 1 0 1| adir | 113 | ORL A,@Ri |0 1 0 0 0 1 1|i| 114 | ORL A,#data |0 1 0 0 0 1 0 0| data | 115 | ORL adir,A |0 1 0 0 0 0 1 0| adir | 116 | ORL adir,#data |0 1 0 0 0 0 1 1| adir | data | 117 | ORL C,bit |0 1 1 1 0 0 1 0| bit | 118 | ORL C,/bit |1 0 1 0 0 0 0 0| bit | 119 | 120 | POP adir |1 1 0 1 0 0 0 0| adir | 121 | PUSH adir |1 1 0 0 0 0 0 0| adir | 122 | 123 | RET - |0 0 1 0 0 0 1 0| 124 | 125 | RETI - |0 0 1 1 0 0 1 0| 126 | 127 | RL A |0 0 1 0 0 0 1 1| 128 | RLC A |0 0 1 1 0 0 1 1| 129 | RR A |0 0 0 0 0 0 1 1| 130 | RRC A |0 0 0 1 0 0 1 1| 131 | 132 | SETB C |1 1 0 1 0 0 1 1| 133 | SETB bit |1 1 0 1 0 0 1 0| abit | 134 | 135 | SJMP arel |1 0 0 0 0 0 0 0| arel | 136 | 137 | SUBB A,Rn |1 0 0 1 1| rn | 138 | SUBB A,adir |1 0 0 1 0 1 0 1| adir | 139 | SUBB A,@Ri |1 0 0 1 0 1 1|i| 140 | SUBB A,#data |1 0 0 1 0 1 0 0| data | 141 | 142 | SWAP A |1 1 0 0 0 1 0 0| 143 | XCH A,Rn |1 1 0 0 1| rn | 144 | XCH A,adir |1 1 0 0 0 1 0 1| adir | 145 | XCH A,@Ri |1 1 0 0 0 1 1|i| 146 | XCHD A,@Ri |1 1 0 1 0 1 1|i| 147 | 148 | XRL A,Rn |0 1 1 0 1| rn | 149 | XRL A,adir |0 1 1 0 0 1 0 1| adir | 150 | XRL A,@Ri |0 1 1 0 0 1 1|i| 151 | XRL A,#data |0 1 1 0 0 1 0 0| data | 152 | XRL adir,A |0 1 1 0 0 0 1 0| adir | 153 | XRL adir,#data |0 1 1 0 0 0 1 1| adir | data | 154 | 155 | -------------------------------------------------------------------------------- /cpus/mcs6500.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # MOS Technology 650x disassembler 4 | # 5 | 6 | from __future__ import print_function 7 | 8 | import const 9 | import disass 10 | 11 | inscode = ( 12 | # 0 1 2 3 4 5 6 7 8 9 a b c d e f 13 | "", "nORA", "", "", "", "zORA", "zASL", "", "_PHP", "iORA", "AASL", "", "", "aORA", "aASL", "", 14 | "rBPL", "mORA", "", "", "", "XORA", "XASL", "", "_CLC", "yORA", "", "", "", "xORA", "xASL", "", 15 | "", "nAND", "", "", "zBIT", "zAND", "zROL", "", "_PLP", "iAND", "AROL", "", "aBIT", "aAND", "aROL", "", 16 | "rBMI", "mAND", "", "", "", "XAND", "XROL", "", "_SEC", "", "", "", "", "xAND", "xROL", "", 17 | 18 | "", "nEOR", "", "", "", "zEOR", "zLSR", "", "_PHA", "iEOR", "ALSR", "", "", "aEOR", "aLSR", "", 19 | "rBVC", "mEOR", "", "", "", "XEOR", "XLSR", "", "_CLI", "yEOR", "", "", "", "xEOR", "xLSR", "", 20 | "", "nADC", "", "", "", "zADC", "zROR", "", "_PLA", "iADC", "AROR", "", "", "aADC", "aROR", "", 21 | "rBVS", "mADC", "", "", "", "XADC", "XROR", "", "_SEI", "yADC", "", "", "", "xADC", "xROR", "", 22 | 23 | "", "nSTA", "", "", "zSTY", "zSTA", "zSTX", "", "_DEY", "", "_TXA", "", "aSTY", "aSTA", "aSTX", "", 24 | "rBCC", "mSTA", "", "", "XSTY", "XSTA", "XSTY", "", "_TYA", "ySTA", "_TXS", "", "", "xSTA", "", "", 25 | "iLDY", "nLDA", "iLDX", "", "zLDY", "zLDA", "zLDX", "", "_TAY", "iLDA", "_TAX", "", "aLDY", "aLDA", "aLDX", "", 26 | "rBCS", "mLDA", "", "", "XLDY", "XLDA", "YLDA", "", "_CLV", "yLDA", "_TSX", "", "", "xLDA", "yLDX", "", 27 | 28 | "iCPY", "nCMP", "", "", "zCPY", "zCMP", "zDEC", "", "_INY", "iCMP", "_DEX", "", "aCPY", "aCMP", "aDEC", "", 29 | "rBNE", "mCMP", "", "", "", "XCMP", "XDEC", "", "_CLD", "yCMP", "", "", "", "xCMP", "xDEC", "", 30 | "iCPX", "nSBC", "", "", "zCPX", "zSBC", "zINC", "", "_INX", "iSBC", "_NOP", "", "aCPX", "aSBC", "aINC", "", 31 | "rBEQ", "mSBC", "", "", "", "XSBC", "XINC", "", "_SED", "ySBC", "", "", "", "xSBC", "xINC", "", 32 | ) 33 | 34 | class mcs6502(disass.assy): 35 | """ 36 | """ 37 | 38 | def __init__(self, p, name = "mcs6502"): 39 | disass.assy.__init__(self, p, name) 40 | assert len(inscode) == 256 41 | 42 | def do_disass(self, adr, ins): 43 | assert ins.lo == adr 44 | assert ins.status == "prospective" 45 | 46 | p = self.p 47 | 48 | try: 49 | iw = p.m.rd(adr) 50 | except: 51 | ins.fail("no mem") 52 | return 53 | 54 | ic = inscode[iw] 55 | #print("%02x " % iw, ic) 56 | if ic == "": 57 | ic = "-" 58 | if ic[0] == "z": 59 | # Page Zero address 60 | ins.mne = ic[1:] 61 | da = p.m.rd(adr + 1) 62 | ins.oper.append((da, "%s", "%02x" % da)) 63 | ins.hi = ins.lo + 2 64 | elif ic[0] == "X": 65 | # PZ,X 66 | da = p.m.rd(adr + 1) 67 | ins.mne = ic[1:] 68 | ins.oper.append((da, "%s", "%02x" % da)) 69 | ins.oper.append("X") 70 | ins.hi = ins.lo + 2 71 | elif ic[0] == "Y": 72 | # PZ,Y 73 | da = p.m.rd(adr + 1) 74 | ins.mne = ic[1:] 75 | ins.oper.append((da, "%s", "%02x" % da)) 76 | ins.oper.append("Y") 77 | ins.hi = ins.lo + 2 78 | elif ic[0] == "i": 79 | # Immediate 80 | ins.mne = ic[1:] 81 | ins.oper.append("#%02x" % p.m.rd(adr + 1)) 82 | ins.hi = ins.lo + 2 83 | elif ic[0] == "a": 84 | # Absolute 85 | da = p.m.l16(adr + 1) 86 | ins.mne = ic[1:] 87 | ins.oper.append("%04x" % da) 88 | ins.hi = ins.lo + 3 89 | elif ic[0] == "x": 90 | # Absolute,X 91 | da = p.m.l16(adr + 1) 92 | ins.mne = ic[1:] 93 | ins.oper.append((da, "%s", "%04x" % da)) 94 | ins.oper.append("X") 95 | ins.hi = ins.lo + 3 96 | elif ic[0] == "y": 97 | # Absolute,Y 98 | da = p.m.l16(adr + 1) 99 | ins.mne = ic[1:] 100 | ins.oper.append((da, "%s", "%04x" % da)) 101 | ins.oper.append("Y") 102 | ins.hi = ins.lo + 3 103 | elif ic[0] == "n": 104 | # (Ind,X) 105 | da = p.m.rd(adr + 1) 106 | ins.mne = ic[1:] 107 | ins.oper.append("(%02x,X)" % da) 108 | ins.hi = ins.lo + 2 109 | elif ic[0] == "m": 110 | # (Ind,Y) 111 | da = p.m.rd(adr + 1) 112 | ins.mne = ic[1:] 113 | ins.oper.append("(%02x,Y)" % da) 114 | ins.hi = ins.lo + 2 115 | elif ic[0] == "r": 116 | # Relative 117 | ins.mne = ic[1:] 118 | da = ins.lo + 2 + p.m.s8(adr + 1) 119 | if da == adr: 120 | ins.mne += "LOOP" 121 | else: 122 | ins.oper.append((da, "%s", "%04x" % da)) 123 | ins.flow("cond", ic[2:], da) 124 | ins.flow("cond", "N" + ic[2:], adr + 2) 125 | ins.hi = ins.lo + 2 126 | elif ic[0] == "A": 127 | # Acc 128 | ins.mne = ic[1:] 129 | ins.oper.append("A") 130 | elif ic[0] == "_": 131 | # Implied 132 | ins.mne = ic[1:] 133 | elif iw == 0x00: 134 | ins.mne = "BRK" 135 | ins.flow("cond", "IRQ", None) 136 | elif iw == 0x20: 137 | ins.mne = "JSR" 138 | da = p.m.l16(adr + 1) 139 | ins.flow("call", "T", da) 140 | ins.oper.append((da, "%s", "%04x" % da)) 141 | ins.hi = ins.lo + 3 142 | elif iw == 0x40: 143 | ins.mne = "RTI" 144 | ins.flow("ret", "IRQ", None) 145 | elif iw == 0x6c: 146 | # JMP (ind) 147 | ins.mne = "JMP" 148 | da = p.m.l16(adr + 1) 149 | ins.oper.append((da, "(%s)", "(%04x)" % da)) 150 | ins.flow("cond", "T", None) 151 | ins.hi = ins.lo + 3 152 | elif iw == 0x4c: 153 | # JMP abs 154 | ins.mne = "JMP" 155 | da = p.m.l16(adr + 1) 156 | ins.oper.append((da, "%s", "%04x" % da)) 157 | ins.flow("cond", "T", da) 158 | ins.hi = ins.lo + 3 159 | elif iw == 0x60: 160 | ins.mne = "RTS" 161 | ins.flow("ret", "T", None) 162 | else: 163 | ins.fail("NYI %02x" % iw) 164 | 165 | 166 | -------------------------------------------------------------------------------- /cpus/nova.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a disassembler for the Data General Nova CPU 4 | # 5 | # self.iodev[device_number] = "device_name" 6 | # Name the I/O devices 7 | # 8 | 9 | from __future__ import print_function 10 | 11 | import disass 12 | import instree 13 | import domus.const as const 14 | 15 | class nova(disass.assy): 16 | def __init__(self, p, name = "nova"): 17 | disass.assy.__init__(self, p, name) 18 | self.root = instree.instree( 19 | width = 16, 20 | filename = __file__[:-3] + "_instructions.txt" 21 | ) 22 | self.iodev = { 23 | 63: "CPU", 24 | } 25 | 26 | def rdarg(self, ins, c, arg): 27 | return c.get_field(self.p, ins.lo, self.p.m.rd, 1, arg) 28 | 29 | def do_disass(self, adr, ins): 30 | assert ins.lo == adr 31 | assert ins.status == "prospective" 32 | 33 | try: 34 | c = self.root.find(self.p, adr, self.p.m.rd) 35 | except: 36 | ins.fail("no memory") 37 | return 38 | 39 | ins.mne = c.spec[0] 40 | da = None 41 | indir = 0 42 | for i in c.spec[1].split(","): 43 | if i == "#": 44 | if self.rdarg(ins, c, i) != 0: 45 | ins.mne += "#" 46 | elif i == "@": 47 | if self.rdarg(ins, c, i) != 0: 48 | ins.mne += "@" 49 | indir = 1 50 | elif i == "sh": 51 | ins.mne += ( 52 | "", "L", "R", "S" 53 | )[self.rdarg(ins, c, i)] 54 | elif i == "cy": 55 | ins.mne += ( 56 | "", "Z", "O", "C" 57 | )[self.rdarg(ins, c, i)] 58 | elif i == "flg": 59 | ins.mne += ( 60 | "", "S", "C", "P" 61 | )[self.rdarg(ins, c, i)] 62 | elif i == "tst": 63 | ins.mne += ( 64 | "BN", "BZ", "DN", "DZ" 65 | )[self.rdarg(ins, c, i)] 66 | elif i == "dev": 67 | ins.oper.append( 68 | self.p.m.dfmt( 69 | self.rdarg(ins, c, i) 70 | ) 71 | ) 72 | elif i == "skip": 73 | j = self.rdarg(ins, c, i) 74 | if j: 75 | ins.oper.append(( 76 | "", "SKP", "SZC", "SNC", 77 | "SZR", "SNR", "SEZ", "SBN" 78 | )[self.rdarg(ins, c, i)]) 79 | if j > 0: 80 | ins.flow("cond", "T", ins.lo + 2) 81 | if j > 1: 82 | ins.flow("cond", "T", ins.lo + 1) 83 | elif i == "acs" or i == "acd": 84 | ins.oper.append("%d" % self.rdarg(ins, c, i)) 85 | elif i == "displ": 86 | r = self.rdarg(ins, c, "idx") 87 | o = self.rdarg(ins, c, "displ") 88 | if r != 0 and o > 128: 89 | o -= 256 90 | if r == 0: 91 | ins.oper.append(( 92 | o, 93 | "%s", 94 | self.p.m.dfmt(o, False) 95 | )) 96 | da = o 97 | elif r == 1: 98 | o += ins.lo 99 | ins.oper.append((o, "%s")) 100 | da = o 101 | else: 102 | ins.oper.append(self.p.m.dfmt(o, False)) 103 | ins.oper.append("%d" % r) 104 | elif i == '""': 105 | pass 106 | else: 107 | print(i, c) 108 | ins.fail("Unhandled arg <%s>" % i) 109 | return 110 | 111 | if da != None and indir: 112 | try: 113 | w = self.p.m.rd(da) 114 | const.word(self.p, da) 115 | if w != 0: 116 | da = w; 117 | else: 118 | da = None 119 | except: 120 | da = None 121 | 122 | # XXX: should also handle SKP instructions masked by macros 123 | if ins.mne[1:3] == "SZ" or ins.mne[:3] == "SKP": 124 | ins.flow("cond", "?", ins.lo + 1) 125 | ins.flow("cond", "?", ins.lo + 2) 126 | elif ins.mne[:3] == "JMP": 127 | ins.flow("cond", "T", da) 128 | elif ins.mne[:3] == "JSR": 129 | ins.flow("call", "T", da) 130 | elif ins.mne == "JMP@" or ins.mne == "JSR@": 131 | if da != None: 132 | try: 133 | da = self.p.m.rd(da) 134 | except: 135 | da = None 136 | if ins.mne == "JMP": 137 | ins.flow("cond", "T", da) 138 | else: 139 | ins.flow("call", "T", da) 140 | -------------------------------------------------------------------------------- /cpus/nova_instructions.txt: -------------------------------------------------------------------------------- 1 | # Nova CPU instructions 2 | 3 | JMP @,displ |0 0 0 0 0|@|idx| displ | 4 | JSR @,displ |0 0 0 0 1|@|idx| displ | 5 | ISZ @,displ |0 0 0 1 0|@|idx| displ | 6 | DSZ @,displ |0 0 0 1 1|@|idx| displ | 7 | LDA acd,@,displ |0 0 1|acd|@|idx| displ | 8 | STA acs,@,displ |0 1 0|acs|@|idx| displ | 9 | ADD cy,sh,#,acs,acd,skip |1|acs|acd|1 1 0|sh |cy |#|skip | 10 | SUB cy,sh,#,acs,acd,skip |1|acs|acd|1 0 1|sh |cy |#|skip | 11 | NEG cy,sh,#,acs,acd,skip |1|acs|acd|0 0 1|sh |cy |#|skip | 12 | ADC cy,sh,#,acs,acd,skip |1|acs|acd|1 0 0|sh |cy |#|skip | 13 | MOV cy,sh,#,acs,acd,skip |1|acs|acd|0 1 0|sh |cy |#|skip | 14 | INC cy,sh,#,acs,acd,skip |1|acs|acd|0 1 1|sh |cy |#|skip | 15 | COM cy,sh,#,acs,acd,skip |1|acs|acd|0 0 0|sh |cy |#|skip | 16 | AND cy,sh,#,acs,acd,skip |1|acs|acd|1 1 1|sh |cy |#|skip | 17 | DIA flg,acd,dev |0 1 1|acd|0 0 1|flg|dev | 18 | DIB flg,acd,dev |0 1 1|acd|0 1 1|flg|dev | 19 | DIC flg,acd,dev |0 1 1|acd|1 0 1|flg|dev | 20 | DOA flg,acs,dev |0 1 1|acs|0 1 0|flg|dev | 21 | DOB flg,acs,dev |0 1 1|acs|1 0 0|flg|dev | 22 | DOC flg,acs,dev |0 1 1|acs|1 1 0|flg|dev | 23 | SKP tst,dev |0 1 1|0 0|1 1 1|tst|dev | 24 | NIO flg,dev |0 1 1|0 0|0 0 0|flg|dev | 25 | INTEN "" |0 1 1|0 0|0 0 0|0 1|1 1 1 1 1 1| 26 | INTDS "" |0 1 1|0 0|0 0 0|1 0|1 1 1 1 1 1| 27 | READS acd |0 1 1|acd|0 0 1|0 0|1 1 1 1 1 1| 28 | INTA acd |0 1 1|acd|0 1 1|0 0|1 1 1 1 1 1| 29 | MSKO acs |0 1 1|acs|1 0 0|0 0|1 1 1 1 1 1| 30 | IORST "" |0 1 1|x x|1 0 1|1 0|1 1 1 1 1 1| 31 | HALT "" |0 1 1|x x|1 1 0|0 0|1 1 1 1 1 1| 32 | -------------------------------------------------------------------------------- /cpus/z80.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Zilog Z-80 disassembler 4 | # 5 | 6 | import instree 7 | import disass 8 | 9 | ####################################################################### 10 | 11 | class z80(disass.assy): 12 | 13 | def __init__(self, p, name = "z80"): 14 | disass.assy.__init__(self, p, name) 15 | self.root = instree.instree( 16 | width = 8, 17 | filename = __file__[:-3] + "_instructions.txt" 18 | ) 19 | self.io_port = dict() 20 | 21 | def do_disass(self, adr, ins): 22 | assert ins.lo == adr 23 | assert ins.status == "prospective" 24 | 25 | p = self.p 26 | 27 | # By default... 28 | ins.hi = ins.lo + 1 29 | 30 | #print(">>> @%04x" % adr, "%02x" % p.m.rd(adr)) 31 | c = self.root.find(p, adr, p.m.rd) 32 | assert c != None 33 | #print(">>>> ", c, "wid",c.width) 34 | ins.hi = ins.lo + (c.width >> 3) 35 | ins.mne = c.spec[0] 36 | #ins.oper = list(c.spec[1].split(",")) 37 | cc = "T" 38 | da = None 39 | for i in c.spec[1].split(","): 40 | if i == "nn": 41 | hi = c.get_field(p, adr, p.m.rd, 1, "n2") 42 | lo = c.get_field(p, adr, p.m.rd, 1, "n1") 43 | da = (hi << 8) | lo 44 | ins.oper.append((da, "%s", "0x%04x" % da)) 45 | elif i == "(nn)": 46 | hi = c.get_field(p, adr, p.m.rd, 1, "n2") 47 | lo = c.get_field(p, adr, p.m.rd, 1, "n1") 48 | da = (hi << 8) | lo 49 | ins.oper.append((da, "%s", "(0x%04x)" % da)) 50 | elif i == "cc": 51 | j = c.get_field(p, adr, p.m.rd, 1, i) 52 | cc = ( 53 | "NZ", "Z", "NC", "C", "PO", "PE", "P", "M" 54 | )[j] 55 | ins.oper.append(cc) 56 | elif i == "dd": 57 | j = c.get_field(p, adr, p.m.rd, 1, i) 58 | ins.oper.append(("BC", "DE", "HL", "SP")[j]) 59 | elif i == "(i)" or i == "(o)": 60 | j = c.get_field(p, adr, p.m.rd, 1, "io") 61 | if j in self.io_port: 62 | k = self.io_port[j] 63 | if len(k) == 2 and i == "(i)": 64 | ins.oper.append("(%s)" % k[0]) 65 | elif len(k) == 2 and i == "(o)": 66 | ins.oper.append("(%s)" % k[1]) 67 | else: 68 | ins.oper.append("(%s)" % k) 69 | else: 70 | ins.oper.append("(0x%02x)" % j) 71 | elif i == "(o)": 72 | j = c.get_field(p, adr, p.m.rd, 1, "i") 73 | if j in self.io_port: 74 | k = self.io_port[j] 75 | if len(k) == 2: 76 | ins.oper.append("(%s)" % k[0]) 77 | else: 78 | ins.oper.append("(%s)" % k) 79 | else: 80 | ins.oper.append("(0x%02x)" % j) 81 | elif i == "n": 82 | j = c.get_field(p, adr, p.m.rd, 1, i) 83 | ins.oper.append("0x%02x" % j) 84 | elif i == "qq": 85 | j = c.get_field(p, adr, p.m.rd, 1, i) 86 | ins.oper.append(("BC", "DE", "HL", "AF")[j]) 87 | elif i in ("rd", "rs"): 88 | j = c.get_field(p, adr, p.m.rd, 1, i) 89 | ins.oper.append(( 90 | "B", "C", "D","E", "H", "L", None, "A" 91 | )[j]) 92 | elif i in ( 93 | "HL", 94 | "A", 95 | "DE", 96 | "SP", 97 | "I", 98 | "0", 99 | "1", 100 | "2", 101 | "(HL)", 102 | "(DE)", 103 | "(BC)", 104 | ): 105 | ins.oper.append(i) 106 | elif i == "-": 107 | pass 108 | else: 109 | print("MISS", i, c) 110 | ins.oper.append(i) 111 | if ins.mne == "RET": 112 | ins.flow("ret", "I", None) 113 | elif ins.mne == "RETI": 114 | ins.flow("ret", "I", None) 115 | elif ins.mne == "JP": 116 | ins.flow("cond", cc, da) 117 | if cc != "T": 118 | ins.flow("cond", "!" + cc, ins.hi) 119 | elif ins.mne == "JR": 120 | ins.flow("cond", cc, da) 121 | if cc != "T": 122 | ins.flow("cond", "!" + cc, ins.hi) 123 | elif ins.mne == "CALL": 124 | ins.flow("call", cc, da) 125 | if cc != "T": 126 | ins.flow("cond", "!" + cc, ins.hi) 127 | -------------------------------------------------------------------------------- /cpus/z8000.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Zilog Z800[12] CPU disassembler 4 | # 5 | 6 | import instree 7 | import disass 8 | 9 | ####################################################################### 10 | 11 | special_registers = { 12 | "FLAGS": True, 13 | "FCW": True, 14 | "PSAOFF": True, 15 | "PSAPSEG": True, 16 | "NSPSEG": True, 17 | "NSPOFF": True, 18 | "REFRESH": True, 19 | } 20 | 21 | condition_codes = { 22 | 0: "F", 8: "T", 23 | 1: "LT", 9: "GE", 24 | 2: "LE", 10: "GT", 25 | 3: "ULE", 11: "UGT", 26 | 4: "OV", 12: "NOV", 27 | 5: "MI", 13: "PL", 28 | 6: "Z", 14: "NZ", 29 | 7: "C", 15: "NC" 30 | } 31 | 32 | class z8000(disass.assy): 33 | 34 | def __init__(self, p, name = "z8000", z8001 = True, segmented = False): 35 | disass.assy.__init__(self, p, name) 36 | if segmented: 37 | assert z8001 38 | self.z8001 = z8001 39 | self.segmented = segmented 40 | self.root = instree.instree( 41 | width = 16, 42 | filename = __file__[:-3] + "_instructions.txt" 43 | ) 44 | 45 | def rdarg(self, p, adr, c, arg): 46 | return c.get_field(p, adr, p.m.b16, 2, arg) 47 | 48 | def get_reg(self, p, adr, arg, c, wid): 49 | if arg in c.flds: 50 | v = self.rdarg(p, adr, c, arg) 51 | elif arg + "!=0" in c.flds: 52 | v = self.rdarg(p, adr, c, arg + "!=0") 53 | if v == 0: 54 | raise disass.DisassError( 55 | "'%s!=0' == 0" % arg, c) 56 | else: 57 | raise disass.DisassError("Not found: '%s'" % arg, c) 58 | if self.segmented and arg[0] == "S": 59 | arg = "R" + arg[1:] 60 | wid = 32 61 | elif arg[0] == "S": 62 | arg = "R" + arg[1:] 63 | wid = 16 64 | 65 | if wid == 64: 66 | if (v & 1) == 3: 67 | raise disass.DisassError("RQ%d" % v, c) 68 | return "RQ%d" % v 69 | if wid == 32: 70 | if (v & 1) == 1: 71 | raise disass.DisassError("RR%d" % v, c) 72 | return "RR%d" % v 73 | if wid == 16: 74 | return "R%d" % v 75 | if wid == 8 and v & 8: 76 | return "RL%d" % (v & 7) 77 | if wid == 8: 78 | return "RH%d" % (v & 7) 79 | 80 | def get_address(self, p, na, tail): 81 | d1 = p.m.b16(na) 82 | na += 2 83 | if not self.segmented: 84 | return(na, (d1, "%s" + tail)) 85 | 86 | if d1 & 0x8000: 87 | assert (d1 & 0xff) == 0 88 | d1 = (d1 & 0x7f00) << 16 89 | d1 |= p.m.b16(na) 90 | na += 2 91 | else: 92 | d1 = (d1 & 0x7f00) << 16 | (d1 & 0x00ff) 93 | 94 | f = "0x%02x:" % (d1 >> 24) 95 | f += "0x%04x" % (d1 & 0xffff) + tail 96 | i = (d1, "%s" + tail, f) 97 | return (na, i) 98 | 99 | def do_disass(self, adr, ins): 100 | assert ins.lo == adr 101 | assert ins.status == "prospective" 102 | 103 | p = self.p 104 | 105 | # By default... 106 | ins.hi = ins.lo + 1 107 | 108 | #print(">>> @%04x" % adr) 109 | c = self.root.find(p, adr, p.m.b16) 110 | 111 | assert c != None 112 | 113 | 114 | # We have a specification in 'c' 115 | self.last_c = c 116 | na = adr + (c.width >> 3) 117 | 118 | mne = c.spec[0] 119 | 120 | # Try to divine the width of this instruction 121 | wid = 16 122 | if mne[-3:] == "CTL": 123 | pass 124 | elif mne == "SLL": 125 | pass 126 | elif mne == "SUB": 127 | pass 128 | elif mne[-1] == "L": 129 | wid = 32 130 | elif mne[-1] == "B": 131 | wid = 8 132 | 133 | i = self.rdarg(p, adr, c, "W") 134 | if i != None: 135 | w = i 136 | if w == 0: 137 | wid = 8 138 | mne += "B" 139 | elif w == 1: 140 | wid = 16 141 | 142 | # Try to divine the src/dest-addr sizes 143 | if self.segmented: 144 | das = 32 145 | sas = 32 146 | else: 147 | das = 16 148 | sas = 16 149 | 150 | if mne[:4] == "OTIR" or mne[:3] == "OUT": 151 | das = 16 152 | 153 | if mne[:2] == "IN" or mne[:4] == "OUTI": 154 | sas = 16 155 | 156 | #print(">>> %04x" % adr, "w%d" % wid, "sa%d" % sas, "da%d" % das, c) 157 | ins.diag = ">>> %04x" % adr + " w%d" % wid + \ 158 | " sa%d" % sas + " da%d" % das + " %s" % str(c) 159 | 160 | ol = list() 161 | cc = None 162 | ncc = None 163 | dstadr = None 164 | for i in c.spec[1].split(","): 165 | y = i 166 | 167 | if i in special_registers: 168 | pass 169 | elif i == '""': 170 | continue 171 | elif i == "Rd" or i == "Sd": 172 | i = self.get_reg(p, adr, i, c, wid) 173 | elif i == "RQd": 174 | i = self.get_reg(p, adr, "RQd", c, 64) 175 | elif i == "RRd": 176 | i = self.get_reg(p, adr, "RRd", c, 32) 177 | elif i == "RRs": 178 | i = self.get_reg(p, adr, "RRs", c, 32) 179 | elif i == "Rbd": 180 | i = self.get_reg(p, adr, "Rbd", c, 8) 181 | elif i == "Rbs": 182 | i = self.get_reg(p, adr, "Rbs", c, 8) 183 | elif i == "Rbl": 184 | i = self.get_reg(p, adr, "Rbl", c, 8) 185 | elif i == "Rs": 186 | i = self.get_reg(p, adr, "Rs", c, wid) 187 | elif i == "Rbd": 188 | assert wid == 8 189 | i = self.get_reg(p, adr, "Rbd", c, 8) 190 | elif i == "int": 191 | j = self.rdarg(p, adr, c, "int") 192 | i = "" % j 193 | elif i == "port": 194 | j = self.rdarg(p, adr, c, "port") 195 | i = "0x%04x" % j 196 | elif i == "#nibble": 197 | j = self.rdarg(p, adr, c, "nibble") 198 | i = "0x%01x" % j 199 | elif i == "S": 200 | j = self.rdarg(p, adr, c, "S") 201 | if j != 0: 202 | mne = "S" + mne 203 | continue 204 | elif i == "flags": 205 | j = self.rdarg(p, adr, c, "flags") 206 | i = "" % j 207 | elif i == "#src": 208 | j = self.rdarg(p, adr, c, "src") 209 | i = "#0x%02x" % j 210 | elif i == "#byte": 211 | j = self.rdarg(p, adr, c, "byte") 212 | i = "0x%02x" % j 213 | elif i == "dispu7": 214 | # D[B]JNZ 215 | j = self.rdarg(p, adr, c, i) 216 | dstadr = na - 2 * j 217 | i = "0x%04x" % dstadr 218 | elif i == "disp8": 219 | j = self.rdarg(p, adr, c, "disp8") 220 | if j > 127: 221 | j -= 256 222 | dstadr = na + 2 * j 223 | i = (dstadr, "%s") 224 | elif i == "disp12": 225 | j = self.rdarg(p, adr, c, "disp12") 226 | if j > 2047: 227 | j -= 4096 228 | dstadr = na - 2 * j 229 | i = "0x%04x" % dstadr 230 | elif i == "disp16": 231 | j = self.rdarg(p, adr, c, "disp16") 232 | if j > 32767: 233 | j -= 65536 234 | dstadr = na + j 235 | i = "0x%04x" % dstadr 236 | elif i == "#S": 237 | j = self.rdarg(p, adr, c, "S") 238 | i = "#%d" % (j + 1) 239 | elif i == "#n": 240 | j = self.rdarg(p, adr, c, "n-1") 241 | i = "#%d" % (j + 1) 242 | elif i == "#b": 243 | j = self.rdarg(p, adr, c, "b") 244 | if mne[:2] == "SL" and j > 127: 245 | mne = "SR" + mne[2:] 246 | j = 65536 - j 247 | i = "%d" % j 248 | elif i == "#data" and wid == 8: 249 | d = p.m.b16(na) 250 | if (d >> 8) != (d & 0xff): 251 | raise disass.DisassError( 252 | "#8bit not duplicated", 253 | "0x%04x" % d) 254 | na += 2 255 | i = "#0x%02x" % (d & 0xff) 256 | elif i == "#data" and wid == 16: 257 | d = p.m.b16(na) 258 | na += 2 259 | i = "#0x%04x" % d 260 | elif i == "#data" and wid == 32: 261 | d = p.m.b32(na) 262 | na += 4 263 | i = (d, "#%s", "#0x%08x" % d) 264 | elif i == "address": 265 | (na, i) = self.get_address(p, na, "") 266 | dstadr = i[0] 267 | elif i == "addr(Rs)": 268 | j = self.get_reg(p, adr, "Rs", c, 16) 269 | (na, i) = self.get_address(p, na, "(%s)" % j) 270 | elif i == "addr(Rd)": 271 | j = self.get_reg(p, adr, "Rd", c, 16) 272 | (na, i) = self.get_address(p, na, "(%s)" % j) 273 | elif i == "@Rs": 274 | i = "@" + self.get_reg(p, adr, "Rs", c, sas) 275 | elif i == "@Rd": 276 | i = "@" + self.get_reg(p, adr, "Rd", c, das) 277 | elif i == "Rs(#disp16)": 278 | rs = self.get_reg(p, adr, "Rs", c, sas) 279 | d16 = self.rdarg(p, adr, c, "disp16") 280 | i = "%s(#0x%04x)" % (rs, d16) 281 | elif i == "Rd(#disp16)": 282 | rd = self.get_reg(p, adr, "Rd", c, das) 283 | d16 = self.rdarg(p, adr, c, "disp16") 284 | i = "%s(#0x%04x)" % (rd, d16) 285 | elif i == "Rd(Rx)": 286 | rd = self.get_reg(p, adr, "Rd", c, das) 287 | rx = self.get_reg(p, adr, "Rx", c, das) 288 | i = "%s(%s)" % (rd, rx) 289 | elif i == "Rs(Rx)": 290 | rs = self.get_reg(p, adr, "Rs", c, das) 291 | rx = self.get_reg(p, adr, "Rx", c, das) 292 | i = "%s(%s)" % (rs, rx) 293 | elif i == "r": 294 | i = self.get_reg(p, adr, "r", c, 16) 295 | elif i == "cc": 296 | v = self.rdarg(p, adr, c, "cc") 297 | cc = condition_codes[v] 298 | ncc = condition_codes[v ^ 8] 299 | i = cc 300 | else: 301 | print(">>> %04x" % adr, wid, sas, das, c) 302 | print(y, "???", i) 303 | ins.fail('Unhandled arg') 304 | return 305 | ol.append(i) 306 | 307 | if mne[0] == "J": 308 | if cc != "F": 309 | ins.flow( "cond", cc, dstadr) 310 | if ncc != "F": 311 | ins.flow( "cond", ncc, na) 312 | if mne == "DJNZ": 313 | ins.flow( "cond", "NZ", dstadr) 314 | ins.flow( "cond", "Z", na) 315 | 316 | if mne == "CALR": 317 | ins.flow( "call", "T", dstadr) 318 | if mne == "CALL": 319 | ins.flow( "call", "T", dstadr) 320 | if mne == "RET" and cc == "T": 321 | ins.flow( "ret", "T", None) 322 | 323 | #if dstadr != None: 324 | # x.a['DA'] = dstadr 325 | 326 | ins.hi = na 327 | ins.mne = mne 328 | ins.oper = ol 329 | -------------------------------------------------------------------------------- /cpus/z80_instructions.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | # -.-.-.-.-.-.-.-|-.-.-.-.-.-.-.- 4 | LD rd,rs |0 1| rd | rs | 5 | LD rd,n |0 0| rd |1 1 0| n | 6 | LD rd,(HL) |0 1| rd |1 1 0| 7 | LD rd,IXd |1 1 0 1 1 1 0 1|0 1| rd |1 1 0| d | 8 | LD rd,IYd |1 1 1 1 1 1 0 1|0 1| rd |1 1 0| d | 9 | LD (HL),rs |0 1 1 1 0| rs | 10 | LD IXd,rs |1 1 0 1 1 1 0 1|0 1 1 1 0| rs | d | 11 | LD IYd,rs |1 1 1 1 1 1 0 1|0 1 1 1 0| rs | d | 12 | LD (HL),n |0 0 1 1 0 1 1 0| n | 13 | LD (IXd),n |1 1 0 1 1 1 0 1|0 0 1 1 0 1 1 0| d | n | 14 | LD (IYd),n |1 1 1 1 1 1 0 1|0 0 1 1 0 1 1 0| d | n | 15 | LD A,(BC) |0 0 0 0 1 0 1 0| 16 | LD A,(DE) |0 0 0 1 1 0 1 0| 17 | LD A,(nn) |0 0 1 1 1 0 1 0| n1 | n2 | 18 | LD (BC),A |0 0 0 0 0 0 1 0| 19 | LD (DE),A |0 0 0 1 0 0 1 0| 20 | LD (nn),A |0 0 1 1 0 0 1 0| n1 | n2 | 21 | LD A,I |1 1 1 0 1 1 0 1|0 1 0 1 0 1 1 1| 22 | LD A,R |1 1 1 0 1 1 0 1|0 1 0 1 1 1 1 1| 23 | LD I,A |1 1 1 0 1 1 0 1|0 1 0 0 0 1 1 1| 24 | LD R,A |1 1 1 0 1 1 0 1|0 1 0 0 1 1 1 1| 25 | LD dd,nn |0 0| dd|0 0 0 1| n1 | n2 | 26 | LD IX,nn |1 1 0 1 1 1 0 1|0 0 1 0 0 0 0 1| n1 | n2 | 27 | LD IY,nn |1 1 1 1 1 1 0 1|0 0 1 0 0 0 0 1| n1 | n2 | 28 | LD HL,(nn) |0 0 1 0 1 0 1 0| n1 | n2 | 29 | LD dd,(nn) |1 1 1 0 1 1 0 1|0 1| dd|1 0 1 1| n1 | n2 | 30 | LD IX,(nn) |1 1 0 1 1 1 0 1|0 0 1 0 1 0 1 0| n1 | n2 | 31 | LD IY,(nn) |1 1 1 1 1 1 0 1|0 0 1 0 1 0 1 0| n1 | n2 | 32 | LD (nn),HL |0 0 1 0 0 0 1 0| n1 | n2 | 33 | LD (nn),dd |1 1 1 0 1 1 0 1|0 1| dd|0 0 1 1| n1 | n2 | 34 | LD (nn),IX |1 1 0 1 1 1 0 1|0 0 1 0 0 0 1 0| n1 | n2 | 35 | LD (nn),IY |1 1 1 1 1 1 0 1|0 0 1 0 0 0 1 0| n1 | n2 | 36 | LD SP,HL |1 1 1 1 1 0 0 1| 37 | LD SP,IX |1 1 0 1 1 1 0 1|1 1 1 1 1 0 0 1| 38 | LD SP,IX |1 1 1 1 1 1 0 1|1 1 1 1 1 0 0 1| 39 | PUSH qq |1 1| qq|0 1 0 1| 40 | PUSH IX |1 1 0 1 1 1 0 1|1 1 1 0 0 1 0 1| 41 | PUSH IY |1 1 1 1 1 1 0 1|1 1 1 0 0 1 0 1| 42 | POP qq |1 1| qq|0 0 0 1| 43 | POP IX |1 1 0 1 1 1 0 1|1 1 1 0 0 0 0 1| 44 | POP IY |1 1 0 1 1 1 0 1|1 1 1 1 1 1 0 1| 45 | EX DE,HL |1 1 1 0 1 0 1 1| 46 | EX AF,AF' |0 0 0 0 1 0 0 0| 47 | EXX - |1 1 0 1 1 0 0 0| 48 | EX (SP),HL |1 1 1 0 0 0 1 1| 49 | EX (SP),IX |1 1 0 1 1 1 0 1|1 1 1 0 0 0 1 1| 50 | EX (SP),IY |1 1 1 1 1 1 0 1|1 1 1 0 0 0 1 1| 51 | LDI - |1 1 1 0 1 1 0 1|1 0 1 0 0 0 0 0| 52 | LDIR - |1 1 1 0 1 1 0 1|1 0 1 1 0 0 0 0| 53 | LDD - |1 1 1 0 1 1 0 1|1 0 1 0 1 0 0 0| 54 | LDDR - |1 1 1 0 1 1 0 1|1 0 1 1 1 0 0 0| 55 | CPI - |1 1 1 0 1 1 0 1|1 0 1 0 0 0 0 1| 56 | CPIR - |1 1 1 0 1 1 0 1|1 0 1 1 0 0 0 1| 57 | CPD - |1 1 1 0 1 1 0 1|1 0 1 0 1 0 0 1| 58 | CPDR - |1 1 1 0 1 1 0 1|1 0 1 1 1 0 0 1| 59 | ADD A,rs |1 0|0 0 0| rs | 60 | ADD A,n |1 1|0 0 0|1 1 0| n | 61 | ADD A,(HL) |1 0|0 0 0|1 1 0| 62 | ADD A,IXd |1 1 0 1 1 1 0 1|1 0|0 0 0|1 1 0| d | 63 | ADD A,IYd |1 1 1 1 1 1 0 1|1 0|0 0 0|1 1 0| d | 64 | 65 | ADC A,rs |1 0|0 0 1| rs | 66 | ADC A,n |1 1|0 0 1|1 1 0| n | 67 | ADC A,(HL) |1 0|0 0 1|1 1 0| 68 | ADC A,IXd |1 1 0 1 1 1 0 1|1 0|0 0 1|1 1 0| d | 69 | ADC A,IYd |1 1 1 1 1 1 0 1|1 0|0 0 1|1 1 0| d | 70 | 71 | SUB A,rs |1 0|0 1 0| rs | 72 | SUB A,n |1 1|0 1 0|1 1 0| n | 73 | SUB A,(HL) |1 0|0 1 0|1 1 0| 74 | SUB A,IXd |1 1 0 1 1 1 0 1|1 0|0 1 0|1 1 0| d | 75 | SUB A,IYd |1 1 1 1 1 1 0 1|1 0|0 1 0|1 1 0| d | 76 | 77 | SBC A,rs |1 0|0 1 1| rs | 78 | SBC A,n |1 1|0 1 1|1 1 0| n | 79 | SBC A,(HL) |1 0|0 1 1|1 1 0| 80 | SBC A,IXd |1 1 0 1 1 1 0 1|1 0|0 1 1|1 1 0| d | 81 | SBC A,IYd |1 1 1 1 1 1 0 1|1 0|0 1 1|1 1 0| d | 82 | 83 | AND A,rs |1 0|1 0 0| rs | 84 | AND A,n |1 1|1 0 0|1 1 0| n | 85 | AND A,(HL) |1 0|1 0 0|1 1 0| 86 | AND A,IXd |1 1 0 1 1 1 0 1|1 0|1 0 0|1 1 0| d | 87 | AND A,IYd |1 1 1 1 1 1 0 1|1 0|1 0 0|1 1 0| d | 88 | 89 | XOR A,rs |1 0|1 0 1| rs | 90 | XOR A,n |1 1|1 0 1|1 1 0| n | 91 | XOR A,(HL) |1 0|1 0 1|1 1 0| 92 | XOR A,IXd |1 1 0 1 1 1 0 1|1 0|1 0 1|1 1 0| d | 93 | XOR A,IYd |1 1 1 1 1 1 0 1|1 0|1 0 1|1 1 0| d | 94 | 95 | OR A,rs |1 0|1 1 0| rs | 96 | OR A,n |1 1|1 1 0|1 1 0| n | 97 | OR A,(HL) |1 0|1 1 0|1 1 0| 98 | OR A,IXd |1 1 0 1 1 1 0 1|1 0|1 1 0|1 1 0| d | 99 | OR A,IYd |1 1 1 1 1 1 0 1|1 0|1 1 0|1 1 0| d | 100 | 101 | CP A,rs |1 0|1 1 1| rs | 102 | CP A,n |1 1|1 1 1|1 1 0| n | 103 | CP A,(HL) |1 0|1 1 1|1 1 0| 104 | CP A,IXd |1 1 0 1 1 1 0 1|1 0|1 1 1|1 1 0| d | 105 | CP A,IYd |1 1 1 1 1 1 0 1|1 0|1 1 1|1 1 0| d | 106 | 107 | INC rd |0 0| rd |1 0 0| 108 | INC (HL) |0 0|1 1 0|1 0 0| 109 | INC IXd |1 1 0 1 1 1 0 1|0 0 1 1 0|1 0 0| d | 110 | INC IYd |1 1 1 1 1 1 0 1|0 0 1 1 0|1 0 0| d | 111 | DEC rd |0 0| rd |1 0 1| 112 | DEC (HL) |0 0|1 1 0|1 0 1| 113 | DEC IXd |1 1 0 1 1 1 0 1|0 0 1 1 0|1 0 1| d | 114 | DEC IYd |1 1 1 1 1 1 0 1|0 0 1 1 0|1 0 1| d | 115 | 116 | DAA - |0 0 1 0 0 1 1 1| 117 | CPL - |0 0 1 0 1 1 1 1| 118 | NEG - |1 1 1 0 1 1 0 1|0 1 0 0 0 1 0 0| 119 | CCF - |0 0 1 1 1 1 1 1| 120 | SCF - |0 0 1 1 0 1 1 1| 121 | NOP - |0 0 0 0 0 0 0 0| 122 | HALT - |0 1 1 1 0 1 1 0| 123 | DI - |1 1 1 1 0 0 1 1| 124 | EI - |1 1 1 1 1 0 1 1| 125 | IM 0 |1 1 1 0 1 1 0 1|0 1 0 0 0 1 1 0| 126 | IM 1 |1 1 1 0 1 1 0 1|0 1 0 1 0 1 1 0| 127 | IM 2 |1 1 1 0 1 1 0 1|0 1 0 1 1 1 1 0| 128 | 129 | ADD HL,dd |0 0| dd|1|0 0 1| 130 | ADC HL,dd |1 1|1 0 1|1 0 1|0 1| dd|1 0 1 0| 131 | SBC HL,dd |1 1|1 0 1|1 0 1|0 1| dd|0 0 1 0| 132 | ADD IX,pp |1 1 0 1 1 1 0 1|0 1| pp|1 0 0 1| 133 | ADD IY,rr |1 1 1 1 1 1 0 1|0 1| rr|1 0 0 1| 134 | INC dd |0 0| dd|0 0 1 1| 135 | INC IX |1 1 0 1 1 1 0 1|0 0 1 0 0 0 1 1| 136 | INC IY |1 1 1 1 1 1 0 1|0 0 1 0 0 0 1 1| 137 | DEC dd |0 0| dd|1 0 1 1| 138 | DEC IX |1 1 0 1 1 1 0 1|0 0 1 0 1 0 1 1| 139 | DEC IY |1 1 1 1 1 1 0 1|0 0 1 0 1 0 1 1| 140 | 141 | RLCA - |0 0 0 0 0 1 1 1| 142 | RLA - |0 0 0 1 0 1 1 1| 143 | RRCA - |0 0 0 0 1 1 1 1| 144 | RRA - |0 0 0 1 1 1 1 1| 145 | 146 | RLC rs |1 1 0 0 1 0 1 1|0 0|0 0 0| rs | 147 | RLC (HL) |1 1 0 0 1 0 1 1|0 0|0 0 0|1 1 0| 148 | RLC IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 0 0|1 1 0| 149 | RLC IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 0 0|1 1 0| 150 | 151 | RL rs |1 1 0 0 1 0 1 1|0 0|0 1 0| rs | 152 | RL (HL) |1 1 0 0 1 0 1 1|0 0|0 1 0|1 1 0| 153 | RL IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 1 0|1 1 0| 154 | RL IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 1 0|1 1 0| 155 | 156 | RRC rs |1 1 0 0 1 0 1 1|0 0|0 0 1| rs | 157 | RRC (HL) |1 1 0 0 1 0 1 1|0 0|0 0 1|1 1 0| 158 | RRC IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 0 1|1 1 0| 159 | RRC IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 0 1|1 1 0| 160 | 161 | RR rs |1 1 0 0 1 0 1 1|0 0|0 1 1| rs | 162 | RR (HL) |1 1 0 0 1 0 1 1|0 0|0 1 1|1 1 0| 163 | RR IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 1 1|1 1 0| 164 | RR IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|0 1 1|1 1 0| 165 | 166 | SLA rs |1 1 0 0 1 0 1 1|0 0|1 0 0| rs | 167 | SLA (HL) |1 1 0 0 1 0 1 1|0 0|1 0 0|1 1 0| 168 | SLA IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|1 0 0|1 1 0| 169 | SLA IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|1 0 0|1 1 0| 170 | 171 | SRA rs |1 1 0 0 1 0 1 1|0 0|1 0 1| rs | 172 | SRA (HL) |1 1 0 0 1 0 1 1|0 0|1 0 1|1 1 0| 173 | SRA IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|1 0 1|1 1 0| 174 | SRA IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|1 0 1|1 1 0| 175 | 176 | SRL rs |1 1 0 0 1 0 1 1|0 0|1 1 1| rs | 177 | SRL (HL) |1 1 0 0 1 0 1 1|0 0|1 1 1|1 1 0| 178 | SRL IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|1 1 1|1 1 0| 179 | SRL IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 0|1 1 1|1 1 0| 180 | 181 | RLD - |1 1 1 0 1 1 0 1|0 1 1 0 1 1 1 1| 182 | RRD - |1 1 1 0 1 1 0 1|0 1 1 0 0 1 1 1| 183 | 184 | BIT b,rs |1 1 0 0 1 0 1 1|0 1| b | rs | 185 | BIT b,(HL) |1 1 0 0 1 0 1 1|0 1| b |1 1 0| 186 | BIT b,IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 1| b |1 1 0| 187 | BIT b,IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |0 1| b |1 1 0| 188 | 189 | SET b,rd |1 1 0 0 1 0 1 1|1 1| b | rd | 190 | SET b,(HL) |1 1 0 0 1 0 1 1|1 1| b |1 1 0| 191 | SET b,IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |1 1| b |1 1 0| 192 | SET b,IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |1 1| b |1 1 0| 193 | 194 | RES b,rd |1 1 0 0 1 0 1 1|1 0| b | rd | 195 | RES b,(HL) |1 1 0 0 1 0 1 1|1 0| b |1 1 0| 196 | RES b,IXd |1 1 0 1 1 1 0 1|1 1 0 0 1 0 1 1| d |1 0| b |1 1 0| 197 | RES b,IYd |1 1 1 1 1 1 0 1|1 1 0 0 1 0 1 1| d |1 0| b |1 1 0| 198 | 199 | JP nn |1 1 0 0 0 0 1 1| n1 | n2 | 200 | JP cc,nn |1 1| cc |0 1 0| n1 | n2 | 201 | JR e |0 0 0 1 1 0 0 0| e | 202 | JR C,e |0 0 1 1 1 0 0 0| e | 203 | JR NC,e |0 0 1 1 0 0 0 0| e | 204 | JR Z,e |0 0 1 0 1 0 0 0| e | 205 | JR NZ,e |0 0 1 0 0 0 0 0| e | 206 | JP (HL) |1 1 1 0 1 0 0 1| 207 | JP (IX) |1 1 0 1 1 1 0 1|1 1 1 0 1 0 0 1| 208 | JP (IY) |1 1 1 1 1 1 0 1|1 1 1 0 1 0 0 1| 209 | DJNZ e |0 0 0 1 0 0 0 0| e | 210 | 211 | CALL nn |1 1 0 0 1 1 0 1| n1 | n2 | 212 | CALL cc,nn |1 1| cc |1 0 0| n1 | n2 | 213 | RET - |1 1 0 0 1 0 0 1| 214 | RET cc |1 1| cc |0 0 0| 215 | RETI - |1 1 1 0 1 1 0 1|0 1 0 0 1 1 0 1| 216 | RETN - |1 1 1 0 1 1 0 1|0 1 0 0 0 1 0 1| 217 | RST t |1 1| t |1 1 1| 218 | 219 | IN A,(i) |1 1 0 1 1 0 1 1| io | 220 | IN r,(C) |1 1 1 0 1 1 0 1|0 1| r |0 0 0| 221 | INI - |1 1 1 0 1 1 0 1|1 0 1 0 0 0 1 0| 222 | INIR - |1 1 1 0 1 1 0 1|1 0 1 1 0 0 1 0| 223 | IND - |1 1 1 0 1 1 0 1|1 0 1 0 1 0 1 0| 224 | INDR - |1 1 1 0 1 1 0 1|1 0 1 1 1 0 1 0| 225 | 226 | OUT (o),A |1 1 0 1 0 0 1 1| io | 227 | OUT (C),r |1 1 1 0 1 1 0 1|0 1| r |0 0 1| 228 | 229 | OUTI - |1 1 1 0 1 1 0 1|1 0 1 0 0 0 1 1| 230 | OUTIR - |1 1 1 0 1 1 0 1|1 0 1 1 0 0 1 1| 231 | OUTD - |1 1 1 0 1 1 0 1|1 0 1 0 1 0 1 1| 232 | OUTDR - |1 1 1 0 1 1 0 1|1 0 1 1 1 0 1 1| 233 | -------------------------------------------------------------------------------- /disass.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | import sys 7 | import bitmap 8 | import copy 9 | 10 | import mem 11 | 12 | ####################################################################### 13 | # 14 | # We report trouble as these exceptions 15 | # 16 | 17 | class DisassError(Exception): 18 | def __init__(self, reason, diag = None): 19 | self.reason = reason 20 | self.diag = diag 21 | self.value = (str(self.reason),) 22 | def __str__(self): 23 | return repr(self.value) 24 | 25 | ####################################################################### 26 | 27 | class disass(object): 28 | """Some kind of execution or interpretation unit. 29 | 30 | This will usually be a CPU, but it can also be interpreters for 31 | the meta-code of high level languages. 32 | """ 33 | def __init__(self, p, name): 34 | self.p = p 35 | self.name = name 36 | self.bm = bitmap.bitmap() 37 | self.ins = dict() 38 | p.c[name] = self 39 | self.fails = 0 40 | self.is_clone = False 41 | self.follow_calls = True 42 | self.special_dst = dict() 43 | 44 | def clone(self, follow_calls = True): 45 | """Make a clone for exploratory purposes 46 | """ 47 | this = copy.copy(self) 48 | this.ins = copy.copy(this.ins) 49 | this.bm = copy.deepcopy(this.bm) 50 | this.fails = 0 51 | this.is_clone = True 52 | this.follow_calls = follow_calls 53 | return this 54 | 55 | def disass(self, adr, priv=None): 56 | """Schedule the address for disassembly 57 | 58 | The instruction is returned immediately, but the 59 | disassembly may not happen until later. 60 | """ 61 | 62 | assert type(adr) == int 63 | 64 | if adr in self.ins: 65 | i = self.ins[adr] 66 | if i.status == "OK": 67 | return i 68 | elif i.status == "new": 69 | return i 70 | elif i.status == "prospective": 71 | return i 72 | elif self.is_clone: 73 | self.fails += 1 74 | return i 75 | 76 | ins = instruction(self, adr) 77 | self.ins[adr] = ins 78 | if self.bm.tst(adr): 79 | ins.status = "overlap" 80 | self.fails += 1 81 | else: 82 | ins.status = "prospective" 83 | self.bm.set(adr) 84 | self.p.todo(adr, self.xxdo_disass, ins) 85 | return ins 86 | 87 | def xxdo_disass(self, p, adr, ins): 88 | assert p == self.p 89 | if ins.status != "prospective": 90 | print(ins) 91 | assert ins.status == "prospective" 92 | assert self.fails != None 93 | if self.fails > 0 and self.is_clone: 94 | ins.fail("cascade") 95 | return 96 | try: 97 | self.do_disass(adr, ins) 98 | except mem.MemError as bug: 99 | ins.fail("no mem", str(bug)) 100 | except DisassError as bug: 101 | ins.fail(bug.reason, bug.diag) 102 | assert self.fails != None 103 | self.finish_ins(ins) 104 | 105 | def is_ins(self, adr): 106 | """Test if we have an instruction on address already 107 | """ 108 | return adr in self.ins 109 | 110 | def new_ins(self, adr): 111 | """Create a new instruction 112 | 113 | Return None if it already exists 114 | Return False if it overlaps an existing instruction 115 | """ 116 | if adr in self.ins: 117 | return None 118 | 119 | if self.bm.tst(adr): 120 | return False 121 | i = instruction(self, adr) 122 | self.bm.set(adr) 123 | self.ins[adr] = i 124 | return i 125 | 126 | def finish_ins(self, ins): 127 | """Finish the definition of an instruction 128 | 129 | """ 130 | assert type(ins.lo) == int 131 | assert type(ins.hi) == int 132 | 133 | if ins.status == "fail": 134 | return 135 | 136 | assert ins.lo >= self.p.lo 137 | assert ins.hi <= self.p.hi 138 | assert self.bm.tst(ins.lo) 139 | assert ins == self.ins[ins.lo] 140 | 141 | if ins.hi > ins.lo + 1 and \ 142 | self.bm.mtst(ins.lo + 1, ins.hi) != False: 143 | self.fails += 1 144 | if self.is_clone: 145 | return 146 | print("ERROR: Overlapping instructions:") 147 | l = list() 148 | ins.status = "overlap" 149 | self.bm.mset(ins.lo, ins.hi) 150 | print("\t", ins) 151 | l.append(ins) 152 | ins.overlap = l 153 | for j in range (ins.lo + 1, ins.hi): 154 | if j in self.ins: 155 | ii = self.ins[j] 156 | print("\t", ii) 157 | ii.status = "overlap" 158 | ii.overlap = l 159 | l.append(ii) 160 | return 161 | 162 | self.bm.mset(ins.lo, ins.hi) 163 | 164 | if ins.status != "prospective": 165 | return 166 | 167 | ins.status = "OK" 168 | 169 | # Only process flow for good instructions 170 | if len(ins.flow_out) == 0: 171 | j = self.disass(ins.hi) 172 | 173 | for i in ins.flow_out: 174 | if type(i[2]) != int: 175 | continue 176 | if not i[2] in self.special_dst: 177 | continue 178 | self.special_dst[i[2]](ins, i[2]) 179 | 180 | has_cond = False 181 | for i in ins.flow_out: 182 | if i[0] == "cond": 183 | has_cond = True 184 | break 185 | 186 | for i in ins.flow_out: 187 | if i[0] == "call": 188 | if not has_cond: 189 | j = self.disass(ins.hi) 190 | if not self.follow_calls: 191 | continue 192 | if type(i[2]) != int: 193 | continue 194 | try: 195 | self.p.m.chkadr(i[2]) 196 | j = self.disass(i[2]) 197 | j.flow_in.append((i[0], i[1], ins.lo)) 198 | except: 199 | pass 200 | 201 | def to_tree(self): 202 | # print("Inserting", self.name, "instructions in tree") 203 | for i in self.ins: 204 | ins = self.ins[i] 205 | if ins.status != "OK": 206 | continue 207 | x = self.p.t.add(ins.lo, ins.hi, "ins") 208 | x.render = self.render 209 | x.a['flow'] = ins.flow_out 210 | x.a['ins'] = ins 211 | if ins.cmt != "": 212 | for i in ins.cmt.split("\n"): 213 | x.cmt.append(i) 214 | 215 | class assy(disass): 216 | """Disassembler for ass' code 217 | 218 | Instructions have .mne and .oper attributes 219 | 220 | Render function does label resolution on .oper elements 221 | of the format: 222 | (int, "foo(%s)") 223 | Substitute label or m.afmt() if "%s" present 224 | (int, "foo(%s)", "bar(%s)") 225 | Substitute label in "foo(%s)" (if "%s" present) 226 | Substitute m.afmt() in "bar(%s)" (if "%s" present) 227 | """ 228 | def __init__(self, p, name): 229 | disass.__init__(self, p, name) 230 | 231 | def disass(self, adr, priv=None): 232 | assert type(adr) == int 233 | j = disass.disass(self, adr, priv) 234 | if j.status == "prospective": 235 | j.mne = None 236 | j.oper = list() 237 | return j 238 | 239 | def render(self, p, ins): 240 | 241 | if type(ins) != instruction: 242 | # transistional hack 243 | ins = ins.a['ins'] 244 | 245 | assert ins.mne != None 246 | assert ins.status == "OK" 247 | s = ins.mne 248 | d = "\t" 249 | for i in ins.oper: 250 | s += d 251 | d = "," 252 | if type(i) == str: 253 | s += i 254 | continue 255 | if type(i[0]) == int: 256 | if i[0] in self.p.label: 257 | s += i[1] % self.p.label[i[0]] 258 | elif len(i) < 3 and i[1].find('%s') != -1: 259 | s += i[1] % self.p.m.afmt(i[0]) 260 | elif len(i) < 3: 261 | s += i[1] 262 | elif i[2].find('%s') != -1: 263 | s += i[2] % self.p.m.afmt(i[0]) 264 | else: 265 | s += i[2] 266 | 267 | else: 268 | s += "" 269 | return (s,) 270 | 271 | class instruction(object): 272 | """A single instruction. 273 | 274 | """ 275 | def __init__(self, disass, adr): 276 | self.disass = disass 277 | self.flow_in = list() 278 | self.flow_out = list() 279 | self.render = None 280 | self.lo = adr 281 | self.hi = adr + 1 282 | self.model = None 283 | self.status = "new" 284 | self.cmt = "" 285 | self.diag = None 286 | self.pseudo = None 287 | 288 | def __repr__(self): 289 | s = " 0: 306 | self.cmt += "\n" 307 | self.cmt += s 308 | 309 | def debug(self): 310 | s = self.__repr__() 311 | 312 | s = s[:-1] 313 | 314 | if len(self.flow_in) > 0: 315 | t = "" 316 | for i in self.flow_in: 317 | s += " <" + self.dflow(i) 318 | t = " " 319 | 320 | if len(self.flow_out) > 0: 321 | t = "" 322 | for i in self.flow_out: 323 | s += " >" + self.dflow(i) 324 | t = " " 325 | 326 | if self.reason != None: 327 | s += " " + str(self.reason) 328 | s += " >" 329 | return s 330 | 331 | def flow(self, mode, cc, dst): 332 | self.flow_out.append((mode, cc, dst)) 333 | 334 | def fail(self, reason, diag = None): 335 | assert self.status == "prospective" 336 | self.status = "fail" 337 | self.reason = reason 338 | if diag != None: 339 | self.diag = diag 340 | if not self.disass.is_clone: 341 | print("FAIL: ", self.debug()) 342 | if self.diag != None: 343 | print("\t", self.diag); 344 | self.disass.fails += 1 345 | -------------------------------------------------------------------------------- /domus/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /domus/const.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | import tree 5 | import mem 6 | 7 | class word(tree.tree): 8 | def __init__(self, p, adr, fmt = None): 9 | tree.tree.__init__(self, adr, adr + 1, "word") 10 | p.t.add(adr, adr + 1, "word", True, self) 11 | self.fmt = fmt 12 | self.render = self.rfunc 13 | 14 | def rfunc(self, p, t): 15 | try: 16 | x = p.m.rd(t.start) 17 | except: 18 | return () 19 | if x in p.label: 20 | return ((".word\t" + p.label[x]),) 21 | q = p.m.rdqual(t.start) 22 | return ((".word\t" + p.m.aqfmt(x, q)),) 23 | 24 | class dot_txt(tree.tree): 25 | def __init__(self, p, start, end = None): 26 | if end == None: 27 | end = start 28 | while True: 29 | a = p.m.rd(end) 30 | if a & 0xff == 0: 31 | end += 1 32 | break 33 | if a >> 8 == 0: 34 | break 35 | end += 1 36 | tree.tree.__init__(self, start, end, "dot_txt") 37 | p.t.add(start, end, "dot_txt", True, self) 38 | self.render = self.rfunc 39 | 40 | def rfunc(self, p, t): 41 | s = ".TXT\t'" 42 | for i in range(t.start, t.end): 43 | q = p.m.rdqual(i) 44 | if q != 1: 45 | raise DomusError(t.start, ".TXT is relocated") 46 | x = p.m.rd(i) 47 | y = x >> 8 48 | if y < 32 or y > 126: 49 | s += "<%d>" % y 50 | else: 51 | s += mem.ascii(y) 52 | y = x & 0xff 53 | if y < 32 or y > 126: 54 | s += "<%d>" % y 55 | else: 56 | s += mem.ascii(y) 57 | s += "'" 58 | return (s,) 59 | -------------------------------------------------------------------------------- /domus/cpu.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | import os 7 | import mem 8 | import cpus.nova 9 | import domus.syscall as domus_syscall 10 | import domus.const as const 11 | 12 | class cpu(cpus.nova.nova): 13 | def __init__(self, p): 14 | cpus.nova.nova.__init__(self, p, "domus") 15 | self.dir = os.path.dirname(__file__) 16 | self.root.load(self.dir + "/domus_funcs.txt") 17 | self.p.loadlabels(self.dir + "/domus_page_zero.txt") 18 | 19 | def pz_entries(self): 20 | i = self.root.root.spec[0] 21 | assert i[0] == 0xffff 22 | pz = dict() 23 | for j in sorted(i[1]): 24 | if j & 0xf700 == 0x0400: 25 | k = i[1][j] 26 | pz[j & 0xff] = k.spec[0] 27 | for i in sorted(pz.keys()): 28 | try: 29 | w = self.p.m.rd(i) 30 | x = const.word(self.p, i) 31 | x.lcmt(pz[i]) 32 | if w != 0: 33 | self.disass(w) 34 | self.p.setlabel(w, pz[i]) 35 | except mem.MemError: 36 | del pz[i] 37 | 38 | fi = open(self.dir + "/domus_page_zero.txt", "r") 39 | for i in fi.readlines(): 40 | i = i.strip() 41 | if i == "" or i[0] == "#": 42 | continue 43 | i = i.split() 44 | j = int(i[1], 0) 45 | if j in pz: 46 | print("PZ", pz[i], i) 47 | continue 48 | try: 49 | w = self.p.m.rd(j) 50 | x = const.word(self.p, j) 51 | x.lcmt(i[0]) 52 | except: 53 | pass 54 | fi.close() 55 | 56 | 57 | 58 | def finish_ins(self, ins): 59 | if ins.mne == "INTPRETE": 60 | if "inter" in self.p.c: 61 | self.p.c["inter"].disass(ins.hi) 62 | else: 63 | print("\n" 64 | "NOTE: This programs uses the " 65 | "DOMUS Interpreter.\n" 66 | "You should load a disassembler " 67 | "for this also (domus.inter.inter)" 68 | "\n" 69 | ) 70 | 71 | ins.flow("cond", "T", None) 72 | 73 | w = self.p.m.rd(ins.lo) 74 | if w & 0xff00 == 0x0400: 75 | # JMP X,0 don't come back... 76 | ins.flow("ret", "INT", None) 77 | 78 | if not ins.mne in domus_syscall.doc: 79 | cpus.nova.nova.finish_ins(self, ins) 80 | return 81 | 82 | d = domus_syscall.doc[ins.mne] 83 | if type(d) == str: 84 | ins.lcmt(d) 85 | elif type(d[0]) == str: 86 | ins.lcmt(d[0]) 87 | else: 88 | for i in d[0]: 89 | ins.lcmt(i) 90 | if type(d) != str and len(d) > 1: 91 | for i in range(0,len(d[1])): 92 | j = d[1][i] 93 | self.p.setlabel(ins.lo + i + 1, "." + j) 94 | ins.flow("cond", j, ins.lo + i + 1) 95 | 96 | cpus.nova.nova.finish_ins(self, ins) 97 | -------------------------------------------------------------------------------- /domus/desc.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | import domus.const as const 5 | 6 | #---------------------------------------------------------------------- 7 | 8 | def do_desc(p, a, l, n, desc): 9 | 10 | if not 'domus_desc' in p.a: 11 | p.a['domus_desc'] = dict() 12 | 13 | id = (a, l, n, desc) 14 | if a in p.a['domus_desc']: 15 | b = p.a['domus_desc'][a] 16 | if b == id: 17 | return False 18 | 19 | print("Redo diff desc @ " + p.m.afmt(a), b, id) 20 | return False 21 | 22 | p.a['domus_desc'][a] = id 23 | 24 | dtype = n + "Descriptor" 25 | 26 | if l == 0: 27 | for i in desc: 28 | try: 29 | p.m.rd(a + l) 30 | except: 31 | break 32 | l += i[0] 33 | x = p.t.add(a, a + l, dtype) 34 | x.blockcmt += n + " descriptor\n" 35 | x.fill = False 36 | i = 0 37 | for j in desc: 38 | if j[1] == "name": 39 | x = const.dot_txt(p, a+i, a + i + j[0]) 40 | else: 41 | x = const.word(p, a + i) 42 | x.cmt.append("+%d " % i + j[1]) 43 | i += j[0] 44 | if i >= l: 45 | break 46 | while i < l: 47 | x = const.word(p, a + i) 48 | x.cmt.append("+%d" % i) 49 | i += 1 50 | return True 51 | 52 | #---------------------------------------------------------------------- 53 | 54 | PageDesc = ( 55 | ( 1, "page size"), 56 | ( 1, "page mask"), 57 | ( 1, "blocking factor"), 58 | ( 1, "page table"), 59 | ( 1, "pagemap"), 60 | ( 1, "statproc"), 61 | ( 1, "first frame"), 62 | ( 1, "top of frames"), 63 | ( 1, "victim"), 64 | ( 1, "pages read"), 65 | ( 1, "pages written"), 66 | ( 1, "pages in"), 67 | ( 1, "pages out"), 68 | ( 1, "adr input mess"), 69 | ( 1, "input message[0]"), 70 | ( 1, "input message[1]"), 71 | ( 1, "input message[2]"), 72 | ( 1, "input message[3]"), 73 | ( 1, "adr output mess"), 74 | ( 1, "output message[0]"), 75 | ( 1, "output message[1]"), 76 | ( 1, "output message[2]"), 77 | ( 1, "output message[3]"), 78 | ( 1, "pager flag"), 79 | ( 1, "working locations"), 80 | ) 81 | 82 | def pagedesc(p, adr, priv = None): 83 | p.a['pagedesc'] = adr 84 | do_desc(p, adr, 0, "Paging", PageDesc) 85 | 86 | w = p.m.rd(adr + 3) 87 | i = p.m.rd(w) 88 | do_desc(p, w, i + 1, "Page_Table", ( 89 | ( 1, "n_pages" ), 90 | ( i, "pageentries"), 91 | )) 92 | 93 | w = p.m.rd(adr + 4) 94 | i = p.m.rd(w) 95 | do_desc(p, w, i + 1, "Page_Map", ( 96 | ( 1, "n_pages" ), 97 | ( i, "pageentries"), 98 | )) 99 | 100 | w = p.m.rd(adr + 5) 101 | if w != 0: 102 | p.setlabel(w, "Paging_Statproc") 103 | priv(w) 104 | 105 | #---------------------------------------------------------------------- 106 | 107 | MsgDesc = ( 108 | ( 1, "next"), 109 | ( 1, "prev"), 110 | ( 1, "chain"), 111 | ( 1, "size"), 112 | ( 1, "sende"), 113 | ( 1, "recei"), 114 | ( 1, "mess0"), 115 | ( 1, "mess1"), 116 | ( 1, "mess2"), 117 | ( 1, "mess3"), 118 | ) 119 | 120 | def msgdesc(p, adr, priv = None): 121 | if adr == 0 or adr == None: 122 | return 123 | if do_desc(p, adr, 10, "Message", MsgDesc): 124 | try: 125 | x = p.m.rd(adr + 2) 126 | except: 127 | return 128 | if x != 0: 129 | p.todo(p.m.rd(adr + 2), msgdesc) 130 | 131 | #---------------------------------------------------------------------- 132 | 133 | ProgDesc = ( 134 | ( 1, "spec"), 135 | ( 1, "start"), 136 | ( 1, "chain"), 137 | ( 1, "size"), 138 | ( 3, "name"), 139 | ) 140 | 141 | def progdesc(p, adr, priv = None): 142 | # 1B0 = 0x8000 = has procdesc 143 | # 1B1 = 0x4000 = reentrant 144 | # 1B5 = params 145 | # 1B6 = paged 146 | # 1B7 = reserve 147 | # 1B15 = 0x0001 = ?? 148 | # Examples: 149 | # MUSIL = 0x8401 150 | # DOMAC = 0x8401 151 | # DOMUS = 0x8000 152 | # SYSG = 0x8400 153 | p.a['progdesc'] = adr 154 | do_desc(p, adr, 0, "Program", ProgDesc) 155 | 156 | #---------------------------------------------------------------------- 157 | 158 | ProcDesc = ( 159 | ( 1, "next"), 160 | ( 1, "prev"), 161 | ( 1, "chain"), 162 | ( 1, "size"), 163 | ( 3, "name"), 164 | ( 1, "first_event"), 165 | ( 1, "last_event"), 166 | ( 1, "buffer"), 167 | ( 1, "program"), 168 | ( 1, "state"), 169 | ( 1, "timer_count"), 170 | ( 1, "priority"), 171 | ( 1, "break_address"), 172 | ( 1, "ac0"), 173 | ( 1, "ac1"), 174 | ( 1, "ac2"), 175 | ( 1, "ac3"), 176 | ( 1, "psw"), 177 | ( 1, "save"), 178 | ( 1, "buf"), 179 | ( 1, "address"), 180 | ( 1, "count"), 181 | ( 1, "reserver"), 182 | ( 1, "conversion_table"), 183 | ( 1, "clear_interrupt"), 184 | ) 185 | 186 | def procdesc(p, adr, priv = None): 187 | print("ProcDesc %x" % adr) 188 | p.a['procdesc'] = adr 189 | do_desc(p, adr, p.m.rd(adr + 3), "Process", ProcDesc) 190 | 191 | msgdesc(p, p.m.rd(adr + 9)) 192 | 193 | progdesc(p, p.m.rd(adr + 10)) 194 | 195 | if priv != None: 196 | # Try the PSW 197 | p.a['psw'] = p.m.rd(adr + 19) >> 1 198 | priv(p.a['psw']) 199 | 200 | # Try the CLEAR_INTERRUPT 201 | try: 202 | cli = p.m.rd(adr + 26) 203 | print("CLI " + p.m.afmt(cli)) 204 | if cli != 0 and priv != None: 205 | priv(cli) 206 | except: 207 | pass 208 | 209 | #---------------------------------------------------------------------- 210 | 211 | ZoneDesc = ( 212 | ( 3, "name"), 213 | ( 1, "size"), 214 | ( 1, "zmode"), 215 | ( 1, "zkind"), 216 | ( 1, "zmask"), 217 | ( 1, "zgive"), 218 | ( 1, "zfile"), 219 | ( 1, "zbloc"), 220 | ( 1, "zconv"), 221 | ( 1, "zbuff"), 222 | ( 1, "zsize"), 223 | ( 1, "zform"), 224 | ( 1, "zleng"), 225 | ( 1, "zfirs"), 226 | ( 1, "ztop"), 227 | ( 1, "zused"), 228 | ( 1, "zshar"), 229 | ( 1, "zrem"), 230 | ( 1, "z0"), 231 | ( 1, "z1"), 232 | ( 1, "z2"), 233 | ( 1, "z3"), 234 | ( 1, "z4"), 235 | ( 1, "z5"), 236 | ( 1, "z"), 237 | ) 238 | 239 | def zonedesc(p, adr, priv = None): 240 | do_desc(p, adr, 0, "Zone", ZoneDesc) 241 | x = p.m.rd(adr + 17) 242 | if x != 0: 243 | sharedesc(p, x) 244 | 245 | #---------------------------------------------------------------------- 246 | 247 | ShareDesc = ( 248 | ( 1, "soper" ), 249 | ( 1, "scount" ), 250 | ( 1, "saddr", ), 251 | ( 1, "sspec", ), 252 | ( 1, "snext", ), 253 | ( 1, "sstat", ), 254 | ( 1, "sfirs", ), 255 | ( 1, "ssize", ), 256 | ) 257 | 258 | def sharedesc(p, adr, priv = None): 259 | do_desc(p, adr, 8, "Share", ShareDesc) 260 | -------------------------------------------------------------------------------- /domus/do_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | #---------------------------------------------------------------------- 5 | # Check the python version 6 | 7 | import sys 8 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 9 | 10 | #---------------------------------------------------------------------- 11 | import os 12 | 13 | import pyreveng 14 | 15 | import domus.cpu 16 | import domus.mem 17 | import domus.inter 18 | import domus.reloc_file 19 | import domus.const as const 20 | import domus.desc as desc 21 | 22 | import render 23 | import topology 24 | 25 | #--------------------------------------------------------------------------- 26 | # Try to locate an executable file 27 | 28 | filedirs = ( 29 | "", 30 | "/rdonly/DDHF/oldcritter/DDHF/DDHF/RC3600/Sw/Rc3600/rc3600/__/", 31 | "/rdonly/DDHF/oldcritter/DDHF/DDHF/RC3600/Sw/rc7000/", 32 | "/rdonly/DDHF/oldcritter/DDHF/DDHF/RC3600/Sw/Rc3600/FILES/", 33 | ) 34 | 35 | def find_file(filename, skip = 0): 36 | for d in filedirs: 37 | try: 38 | load_file = domus.reloc_file.reloc_file( 39 | d + filename, 40 | skip 41 | ) 42 | no = load_file.build_index() 43 | assert len(no) != 0 44 | print("Loaded file: " + filename) 45 | if d != "": 46 | print("From: " + d) 47 | s = os.path.basename(d + filename) 48 | if s[:3] == "__.": 49 | s = s[3:] 50 | print("Basename: " + s) 51 | print() 52 | load_file.basename = s 53 | if len(no) > 1: 54 | print( 55 | "This is library file " 56 | "with %d objects" % len(no) 57 | ) 58 | load_file.library = True 59 | else: 60 | load_file.library = False 61 | return load_file 62 | except: 63 | pass 64 | return None 65 | 66 | #--------------------------------------------------------------------------- 67 | 68 | def load_obj(load_file, obj, silent=True): 69 | 70 | m = domus.mem.mem_domus() 71 | load_file.load(m, obj, silent=silent) 72 | m.hex = True 73 | 74 | p = pyreveng.pyreveng(m) 75 | cpu = domus.cpu.cpu(p) 76 | ld = load_file.rec_end 77 | p.a['library'] = load_file.library 78 | p.a['objname'] = obj 79 | p.a['basename'] = load_file.basename 80 | p.a['entrypoint'] = ld 81 | if obj == None: 82 | print("Loaded object from: " + load_file.basename) 83 | else: 84 | print("Loaded " + obj + " from: " + load_file.basename) 85 | print() 86 | return p 87 | 88 | #--------------------------------------------------------------------------- 89 | 90 | def pz_entry(p, cpu): 91 | # XXX: does not work right now 92 | return 93 | for i in range(0,256): 94 | try: 95 | q = p.m.rdqual(i) 96 | d = p.m.rd(i) 97 | except: 98 | continue 99 | if q > 0: 100 | cpu.disass(d) 101 | continue 102 | j = 0o006200 | i 103 | if j in cpu.special: 104 | p.setlabel(d, cpu.special[j][0]) 105 | x = p.t.add(i, i + 1, "PZ_CALL") 106 | x.render = ".WORD %o%s" % (d, p.m.qfmt(q)) 107 | x.blockcmt += "\n" 108 | x.cmt.append(cpu.special[j][0]) 109 | if len(cpu.special[j]) > 1: 110 | for k in cpu.special[j][1]: 111 | x.cmt.append(k) 112 | 113 | 114 | #--------------------------------------------------------------------------- 115 | 116 | def auto_magic(p): 117 | cpu = p.c["domus"] 118 | ld = p.a['entrypoint'] 119 | if ld == None: 120 | pass 121 | elif ld == 0x8000: 122 | pass 123 | elif p.a['library'] == True: 124 | cpu.disass(ld) 125 | else: 126 | desc.procdesc(p, ld, cpu.disass) 127 | p.run() 128 | 129 | #--------------------------------------------------------------------------- 130 | 131 | def auto_hints(p): 132 | id = p.a['basename'] 133 | objname = p.a['objname'] 134 | if objname != None: 135 | id += "_" + objname 136 | try: 137 | exec("import domus.hints." + id + " as hint\nhint.hint(p)") 138 | print("Hints loaded from domus.hints.%s" % id) 139 | p.run() 140 | except ImportError as x: 141 | if x.args[0] == "No module named " + id: 142 | print("No auto hints found (domus.hints.%s)" % id) 143 | else: 144 | assert False 145 | print() 146 | 147 | #--------------------------------------------------------------------------- 148 | 149 | def finish(p): 150 | 151 | p.run() 152 | 153 | for i in p.c: 154 | p.c[i].to_tree() 155 | 156 | ff = topology.topology(p) 157 | ff.build_bb() 158 | ff.segment() 159 | ff.dump_dot( 160 | digraph='size="7.00, 10.80"\nconcentrate=true\ncenter=true\n' 161 | ) 162 | 163 | r = render.render(p) 164 | r.add_flows() 165 | 166 | if p.a['objname'] != None: 167 | fn = "/tmp/_." + p.a['basename'] + "_" + p.a['objname'] 168 | else: 169 | fn = "/tmp/_." + p.a['basename'] 170 | fn += ".txt" 171 | print("Output written to:", fn) 172 | r.render(fn) 173 | -------------------------------------------------------------------------------- /domus/domus_funcs.txt: -------------------------------------------------------------------------------- 1 | # Machine generated file, see rd_mupar.py 2 | 3 | .NEXTOPERATION "" |0|0|0|0|0|1|0|0|0|1|1|1|0|1|0|0| 4 | .RETURNANSWER "" |0|0|0|0|0|1|0|0|0|1|1|1|0|1|0|1| 5 | .CLEARDEVICE "" |0|0|0|0|0|1|0|0|0|1|1|1|0|1|1|0| 6 | .SETINTERRUPT "" |0|0|0|0|0|1|0|0|0|1|1|1|1|0|0|0| 7 | .SETRESERVATION "" |0|0|0|0|0|1|0|0|0|1|1|1|1|0|0|1| 8 | .SETCONVERSION "" |0|0|0|0|0|1|0|0|0|1|1|1|1|0|1|0| 9 | .CONBYTE "" |0|0|0|0|0|1|0|0|0|1|1|1|1|0|1|1| 10 | .GETBYTE "" |0|0|0|0|0|1|0|0|0|1|1|1|1|1|0|0| 11 | .PUTBYTE "" |0|0|0|0|0|1|0|0|0|1|1|1|1|1|0|1| 12 | .MULTIPLY "" |0|0|0|0|0|1|0|0|0|1|1|1|1|1|1|0| 13 | .DIVIDE "" |0|0|0|0|0|1|0|0|0|1|1|1|1|1|1|1| 14 | .GETREC "" |0|0|0|0|0|1|0|0|1|0|0|0|0|0|0|0| 15 | .PUTREC "" |0|0|0|0|0|1|0|0|1|0|0|0|0|0|0|1| 16 | .WAITTRANSFER "" |0|0|0|0|0|1|0|0|1|0|0|0|0|0|1|0| 17 | .REPEATSHARE "" |0|0|0|0|0|1|0|0|1|0|0|0|0|0|1|1| 18 | .TRANSFER "" |0|0|0|0|0|1|0|0|1|0|0|0|0|1|0|0| 19 | .INBLOCK "" |0|0|0|0|0|1|0|0|1|0|0|0|0|1|0|1| 20 | .OUTBLOCK "" |0|0|0|0|0|1|0|0|1|0|0|0|0|1|1|0| 21 | .INCHAR "" |0|0|0|0|0|1|0|0|1|0|0|0|0|1|1|1| 22 | .FREESHARE "" |0|0|0|0|0|1|0|0|1|0|0|0|1|0|0|0| 23 | .OUTSPACE "" |0|0|0|0|0|1|0|0|1|0|0|0|1|0|0|1| 24 | .OUTCHAR "" |0|0|0|0|0|1|0|0|1|0|0|0|1|0|1|0| 25 | .OUTNL "" |0|0|0|0|0|1|0|0|1|0|0|0|1|0|1|1| 26 | .OUTEND "" |0|0|0|0|0|1|0|0|1|0|0|0|1|1|0|0| 27 | .OUTTEXT "" |0|0|0|0|0|1|0|0|1|0|0|0|1|1|0|1| 28 | .OUTOCTAL "" |0|0|0|0|0|1|0|0|1|0|0|0|1|1|1|0| 29 | .SETPOSITION "" |0|0|0|0|0|1|0|0|1|0|0|0|1|1|1|1| 30 | .CLOSE "" |0|0|0|0|0|1|0|0|1|0|0|1|0|0|0|0| 31 | .OPEN "" |0|0|0|0|0|1|0|0|1|0|0|1|0|0|0|1| 32 | CNEXTINTER "" |0|0|0|0|0|1|0|0|1|0|0|1|1|1|0|0| 33 | NEXTINTER "" |0|0|0|0|0|1|0|0|1|0|0|1|1|1|0|1| 34 | WAIT "" |0|0|0|0|1|1|0|0|0|0|0|0|0|0|1|0| 35 | WAITINTERRUPT "" |0|0|0|0|1|1|0|0|0|0|0|0|0|0|1|1| 36 | SENDMESSAGE "" |0|0|0|0|1|1|0|0|0|0|0|0|0|1|0|0| 37 | WAITANSWER "" |0|0|0|0|1|1|0|0|0|0|0|0|0|1|0|1| 38 | WAITEVENT "" |0|0|0|0|1|1|0|0|0|0|0|0|0|1|1|0| 39 | SENDANSWER "" |0|0|0|0|1|1|0|0|0|0|0|0|0|1|1|1| 40 | SEARCHITEM "" |0|0|0|0|1|1|0|0|0|0|0|0|1|0|0|0| 41 | CLEANPROCESS "" |0|0|0|0|1|1|0|0|0|0|0|0|1|0|0|1| 42 | BREAKPROCESS "" |0|0|0|0|1|1|0|0|0|0|0|0|1|0|1|0| 43 | STOPPROCESS "" |0|0|0|0|1|1|0|0|0|0|0|0|1|0|1|1| 44 | STARTPROCESS "" |0|0|0|0|1|1|0|0|0|0|0|0|1|1|0|0| 45 | RECHAIN "" |0|0|0|0|1|1|0|0|0|0|0|0|1|1|0|1| 46 | NEXTOPERATION "" |0|0|0|0|1|1|0|0|0|1|1|1|0|1|0|0| 47 | RETURNANSWER "" |0|0|0|0|1|1|0|0|0|1|1|1|0|1|0|1| 48 | WAITOPERATION "" |0|0|0|0|1|1|0|0|0|1|1|1|0|1|1|1| 49 | SETINTERRUPT "" |0|0|0|0|1|1|0|0|0|1|1|1|1|0|0|0| 50 | SETRESERVATION "" |0|0|0|0|1|1|0|0|0|1|1|1|1|0|0|1| 51 | SETCONVERSION "" |0|0|0|0|1|1|0|0|0|1|1|1|1|0|1|0| 52 | CONBYTE "" |0|0|0|0|1|1|0|0|0|1|1|1|1|0|1|1| 53 | GETBYTE "" |0|0|0|0|1|1|0|0|0|1|1|1|1|1|0|0| 54 | PUTBYTE "" |0|0|0|0|1|1|0|0|0|1|1|1|1|1|0|1| 55 | MULTIPLY "" |0|0|0|0|1|1|0|0|0|1|1|1|1|1|1|0| 56 | DIVIDE "" |0|0|0|0|1|1|0|0|0|1|1|1|1|1|1|1| 57 | GETREC "" |0|0|0|0|1|1|0|0|1|0|0|0|0|0|0|0| 58 | PUTREC "" |0|0|0|0|1|1|0|0|1|0|0|0|0|0|0|1| 59 | WAITTRANSFER "" |0|0|0|0|1|1|0|0|1|0|0|0|0|0|1|0| 60 | TRANSFER "" |0|0|0|0|1|1|0|0|1|0|0|0|0|1|0|0| 61 | INBLOCK "" |0|0|0|0|1|1|0|0|1|0|0|0|0|1|0|1| 62 | OUTBLOCK "" |0|0|0|0|1|1|0|0|1|0|0|0|0|1|1|0| 63 | INCHAR "" |0|0|0|0|1|1|0|0|1|0|0|0|0|1|1|1| 64 | FREESHARE "" |0|0|0|0|1|1|0|0|1|0|0|0|1|0|0|0| 65 | OUTSPACE "" |0|0|0|0|1|1|0|0|1|0|0|0|1|0|0|1| 66 | OUTCHAR "" |0|0|0|0|1|1|0|0|1|0|0|0|1|0|1|0| 67 | OUTNL "" |0|0|0|0|1|1|0|0|1|0|0|0|1|0|1|1| 68 | OUTEND "" |0|0|0|0|1|1|0|0|1|0|0|0|1|1|0|0| 69 | OUTTEXT "" |0|0|0|0|1|1|0|0|1|0|0|0|1|1|0|1| 70 | OUTOCTAL "" |0|0|0|0|1|1|0|0|1|0|0|0|1|1|1|0| 71 | SETPOSITION "" |0|0|0|0|1|1|0|0|1|0|0|0|1|1|1|1| 72 | CLOSE "" |0|0|0|0|1|1|0|0|1|0|0|1|0|0|0|0| 73 | OPEN "" |0|0|0|0|1|1|0|0|1|0|0|1|0|0|0|1| 74 | WAITZONE "" |0|0|0|0|1|1|0|0|1|0|0|1|0|0|1|0| 75 | INNAME "" |0|0|0|0|1|1|0|0|1|0|0|1|0|0|1|1| 76 | MOVE "" |0|0|0|0|1|1|0|0|1|0|0|1|0|1|0|0| 77 | INTPRETE "" |0|0|0|0|1|1|0|0|1|0|0|1|0|1|0|1| 78 | BINDEC "" |0|0|0|0|1|1|0|0|1|0|0|1|1|0|1|0| 79 | DECBIN "" |0|0|0|0|1|1|0|0|1|0|0|1|1|0|1|1| 80 | TAKEA "" |0|0|0|0|1|1|0|0|1|0|0|1|1|1|1|0| 81 | TAKEV "" |0|0|0|0|1|1|0|0|1|0|0|1|1|1|1|1| 82 | NEWCAT "" |0|0|0|0|1|1|0|0|1|1|0|1|1|0|1|0| 83 | FREECAT "" |0|0|0|0|1|1|0|0|1|1|0|1|1|0|1|1| 84 | CDELAY "" |0|0|0|0|1|1|0|0|1|1|0|1|1|1|0|0| 85 | WAITSE "" |0|0|0|0|1|1|0|0|1|1|0|1|1|1|0|1| 86 | WAITCH "" |0|0|0|0|1|1|0|0|1|1|0|1|1|1|1|0| 87 | CWANSW "" |0|0|0|0|1|1|0|0|1|1|0|1|1|1|1|1| 88 | CTEST "" |0|0|0|0|1|1|0|0|1|1|1|0|0|0|0|0| 89 | CPRINT "" |0|0|0|0|1|1|0|0|1|1|1|0|0|0|0|1| 90 | CTOUT "" |0|0|0|0|1|1|0|0|1|1|1|0|0|0|1|0| 91 | SIGNAL "" |0|0|0|0|1|1|0|0|1|1|1|0|0|0|1|1| 92 | SIGCH "" |0|0|0|0|1|1|0|0|1|1|1|0|0|1|0|0| 93 | CPASS "" |0|0|0|0|1|1|0|0|1|1|1|0|0|1|0|1| 94 | CREATEENTRY "" |0|0|0|0|1|1|0|0|1|1|1|0|0|1|1|0| 95 | LOOKUPENTRY "" |0|0|0|0|1|1|0|0|1|1|1|0|0|1|1|1| 96 | CHANGEENTRY "" |0|0|0|0|1|1|0|0|1|1|1|0|1|0|0|0| 97 | REMOVEENTRY "" |0|0|0|0|1|1|0|0|1|1|1|0|1|0|0|1| 98 | INITCATALOG "" |0|0|0|0|1|1|0|0|1|1|1|0|1|0|1|0| 99 | SETENTRY "" |0|0|0|0|1|1|0|0|1|1|1|0|1|0|1|1| 100 | COMON "" |0|0|0|0|1|1|0|0|1|1|1|0|1|1|0|0| 101 | CALL "" |0|0|0|0|1|1|0|0|1|1|1|0|1|1|0|1| 102 | GOTO "" |0|0|0|0|1|1|0|0|1|1|1|0|1|1|1|0| 103 | GETADR "" |0|0|0|0|1|1|0|0|1|1|1|0|1|1|1|1| 104 | GETPOINT "" |0|0|0|0|1|1|0|0|1|1|1|1|0|0|0|0| 105 | CSENDM "" |0|0|0|0|1|1|0|0|1|1|1|1|0|1|0|0| 106 | SIGGEN "" |0|0|0|0|1|1|0|0|1|1|1|1|0|1|0|1| 107 | WAITGE "" |0|0|0|0|1|1|0|0|1|1|1|1|0|1|1|0| 108 | CTOP "" |0|0|0|0|1|1|0|0|1|1|1|1|0|1|1|1| 109 | -------------------------------------------------------------------------------- /domus/domus_page_zero.txt: -------------------------------------------------------------------------------- 1 | # Machine generated file, see rd_mupar.py 2 | 3 | CUR 0x0020 4 | TABLE 0x0025 5 | TOPTA 0x0026 6 | PFIRS 0x002a 7 | RUNNI 0x002c 8 | .0 0x002d 9 | EXIT 0x002e 10 | EFIRS 0x002f 11 | FFIRS 0x0030 12 | DELAY 0x0031 13 | AREAP 0x0034 14 | AFIRS 0x0035 15 | FREQU 0x0036 16 | MASK 0x0037 17 | CORES 0x0038 18 | PROGR 0x0039 19 | RTIME 0x003c 20 | POWIN 0x003e 21 | CDUMP 0x003f 22 | CPUTY 0x0040 23 | BIT 0x0041 24 | .1B1 0x0042 25 | .1B2 0x0043 26 | .1B3 0x0044 27 | .1B4 0x0045 28 | .1B5 0x0046 29 | .1B6 0x0047 30 | .1B7 0x0048 31 | .1B8 0x0049 32 | .1B9 0x004a 33 | .1B10 0x004b 34 | .1B11 0x004c 35 | .1B12 0x004d 36 | .1B13 0x004e 37 | .1B14 0x004f 38 | .1B15 0x0050 39 | .3 0x0051 40 | .5 0x0052 41 | .6 0x0053 42 | .7 0x0054 43 | .9 0x0055 44 | .10 0x0056 45 | .12 0x0057 46 | .13 0x0058 47 | .15 0x0059 48 | .24 0x005a 49 | .25 0x005b 50 | .40 0x005c 51 | .48 0x005d 52 | .56 0x005e 53 | .60 0x005f 54 | .63 0x0060 55 | .120 0x0061 56 | .127 0x0062 57 | .255 0x0063 58 | .M3 0x0064 59 | .M4 0x0065 60 | .M16 0x0066 61 | .M256 0x0067 62 | INTGIVEUP 0x0096 63 | RINTGIVEUP 0x0097 64 | INTBREAK 0x0098 65 | RINTBREAK 0x0099 66 | PINTBREAK 0x00a0 67 | PRINTBREAK 0x00a1 68 | CORE 0x00f1 69 | COMLIST 0x00f2 70 | COMNO 0x00f3 71 | -------------------------------------------------------------------------------- /domus/hints/CATW_CATW.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | import domus.const as const 4 | 5 | def hint(p): 6 | cpu = p.c["domus"] 7 | # See RCSL 43-GL-7915 p35 8 | pgd = p.a['progdesc'] 9 | print("CATW", pgd) 10 | x = const.word(p, pgd + 7) 11 | x.cmt.append(" +7 First Area Process") 12 | x = const.word(p, pgd + 8) 13 | x.cmt.append(" +8 Top Area Process") 14 | x = const.word(p, pgd + 9) 15 | x.cmt.append(" +9 Head of Unit Chain") 16 | x = const.word(p, pgd + 10) 17 | x.cmt.append(" +10 Chain of Head of Unit Chain") 18 | a = pgd + 11 19 | while True: 20 | x = p.t.add(a, a + 20, "UnitDesc") 21 | 22 | x = const.word(p, a) 23 | x.cmt.append(" +0 Driver name reference") 24 | 25 | x = const.word(p, a + 1) 26 | x.cmt.append(" +1 Unit number") 27 | 28 | x = const.word(p, a + 2) 29 | x.cmt.append(" +2 chain") 30 | 31 | x = const.word(p, a + 3) 32 | x.cmt.append(" +3 size of unit desc") 33 | 34 | x = const.dot_txt(p, a + 4, a + 7) 35 | x = const.dot_txt(p, a + 7, a + 10) 36 | 37 | x = const.word(p, a + 10) 38 | x.cmt.append(" +10 Kit displacement") 39 | x = const.word(p, a + 11) 40 | x.cmt.append(" +11 Kit displacement") 41 | 42 | n = p.m.rd(a + 2) 43 | if n == 0: 44 | break 45 | a = n 46 | 47 | -------------------------------------------------------------------------------- /domus/hints/DOMUS_S0303.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | import domus.desc 4 | import domus.const 5 | 6 | def hint(p): 7 | p.m.hex = True 8 | cpu = p.c["domus"] 9 | 10 | p.a['page_base'] = 0x137a 11 | domus.desc.pagedesc(p, 0x1007, cpu.disass) 12 | for pg in range(3, 20): 13 | aa = p.a['page_base'] + pg * 0x100 14 | domus.const.word(p, aa) 15 | print(pg, aa) 16 | x = p.t.add(aa, aa + 0x100, "page %d" % pg) 17 | 18 | for c in range(0,19): 19 | aa = 0x1d90 + 5 * c 20 | domus.const.word(p, aa) 21 | domus.const.dot_txt(p, aa + 1, aa + 4) 22 | domus.const.word(p, aa + 4) 23 | nw = p.m.rd(aa) 24 | da = (nw & 0x7fff) + p.a['page_base'] 25 | cpu.disass(da) 26 | -------------------------------------------------------------------------------- /domus/hints/INT_INT14.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | import domus.inter.inter as inter 4 | import domus.const as const 5 | 6 | def hint(p): 7 | p.m.hex = False 8 | cpu = p.c["domus"] 9 | tbl_base = 0x800d 10 | 11 | # "PINTGIVEUP" ? 12 | cpu.disass(0xa0) 13 | 14 | def xx(n): 15 | i = n + tbl_base 16 | x = inter.intins[n] 17 | y = const.word(p,i) 18 | id = "op=%d: " % n + x[1] + str(x[2:]) 19 | y.cmt.append(id) 20 | a = p.m.rd(i) 21 | if len(x) == 2: 22 | p.setlabel(a, x[1] + " **********") 23 | else: 24 | p.setlabel(a, x[1]) 25 | x = p.m.rd(i) 26 | if x != 0: 27 | ins = cpu.ins[0x800c] 28 | ins.flow("cond", "#%d" % n, x) 29 | z = cpu.disass(x) 30 | z.lcmt(id) 31 | 32 | for i in inter.intins: 33 | xx(i) 34 | 35 | p.setlabel(0x1000, "TxtBreak") 36 | const.dot_txt(p, 0x1000, 0x1005) 37 | 38 | p.setlabel(0x1005, "TxtError") 39 | const.dot_txt(p, 0x1005, 0x100a) 40 | 41 | p.setlabel(0o100267, "Execute") 42 | p.setlabel(0o100273, "GetZoneAddr") 43 | p.setlabel(0o100371, "TakeAidxV") 44 | p.setlabel(0o100407, "Take2Addr") 45 | p.setlabel(0o100644, "Send2Oper") 46 | p.setlabel(0o100654, "_OperMsg") 47 | 48 | p.setlabel(0o101117, "IntGiveup") 49 | cpu.disass(0o101117) 50 | 51 | p.setlabel(0o101131, "PIntGiveup") 52 | cpu.disass(0o101131) 53 | 54 | # Empty table entries 55 | const.word(p, 0o100361) 56 | const.word(p, 0o100362) 57 | 58 | # Operator Message 59 | const.word(p, 0o100654) 60 | const.word(p, 0o100655) 61 | const.word(p, 0o100656) 62 | const.word(p, 0o100657) 63 | const.word(p, 0o100660) 64 | 65 | const.dot_txt(p, 0o101270, 0o101271) 66 | const.dot_txt(p, 0o101271, 0o101272) 67 | for i in range(0o101272, 0o101277): 68 | const.word(p, i) 69 | for i in (0o100325, 0o101331): 70 | const.word(p, i) 71 | const.dot_txt(p, 0o101332, 0o101333) 72 | 73 | 74 | -------------------------------------------------------------------------------- /domus/hints/LIBE_OBJ00.py: -------------------------------------------------------------------------------- 1 | 2 | import domus.const as const 3 | 4 | def hint(p): 5 | const.dot_txt(p, 0o10015, None) 6 | 7 | -------------------------------------------------------------------------------- /domus/hints/MUC_MUC03.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | def hint(p): 4 | cpu = p.c["domus"] 5 | cpu.disass(0o100013) 6 | cpu.disass(0o100025) 7 | cpu.disass(0o100026) 8 | cpu.disass(0o100017) 9 | cpu.disass(0o100034) 10 | 11 | -------------------------------------------------------------------------------- /domus/hints/MUSIL_CMP10.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | import domus.const as const 4 | import domus.desc as desc 5 | import domus.inter.inter 6 | 7 | def follow_chain(p, a, f = None): 8 | while a != 0: 9 | if f != None: 10 | f(p, a) 11 | x = const.word(p, a + 2) 12 | x.lcmt("+2 CHAIN") 13 | x = const.dot_txt(p, a + 4, a + 7) 14 | x.lcmt("+4 NAME") 15 | a = p.m.rd(a + 2) 16 | 17 | def hunt_outtext(p, cpu): 18 | """ A very crude value tracker for system calls 19 | """ 20 | 21 | did = dict() 22 | for i in cpu.ins: 23 | ins = cpu.ins[i] 24 | w = p.m.rd(ins.lo) 25 | if w & 0xff00 != 0x0c00: 26 | continue 27 | 28 | ac = [None,None,None,None] 29 | x = i-1 30 | while x in cpu.ins: 31 | ins1 = cpu.ins[x] 32 | if ins1.mne != "LDA": 33 | #print("!", cpu.render(p, ins1)) 34 | break 35 | if len(ins1.oper) != 2: 36 | #print("!", cpu.render(p, ins1)) 37 | break 38 | n = int(ins1.oper[0]) 39 | ac[n] = ins1.oper[1][0] 40 | const.word(p, ac[n]) 41 | x -= 1 42 | 43 | if ac == [None,None,None,None]: 44 | continue 45 | 46 | s = p.m.afmt(i) 47 | s += " " 48 | s += cpu.render(p, ins)[0] 49 | s += " " 50 | for j in range(0,4): 51 | i = ac[j] 52 | if i != None: 53 | s += " AC%d=" % j + p.m.afmt(i) 54 | try: 55 | w = p.m.rd(i) 56 | q = p.m.rdqual(i) 57 | s += "=" + p.m.aqfmt(w, q) 58 | except: 59 | s += "=undef" 60 | 61 | print(s) 62 | if ins.mne == "SEARCHITEM": 63 | if ac[1] != None: 64 | try: 65 | w = p.m.rd(ac[1]) 66 | print(" HEAD", 67 | p.m.afmt(ac[1]), p.m.afmt(w)) 68 | const.word(p, w + 2) 69 | except: 70 | pass 71 | 72 | if ac[2] != None: 73 | w = p.m.rd(ac[2]) 74 | print(" NAME", p.m.afmt(ac[2]), p.m.afmt(w)) 75 | try: 76 | const.dot_txt(p, w, w + 3) 77 | except: 78 | pass 79 | if ins.mne == "SENDMESSAGE": 80 | if ac[1] != None: 81 | w = p.m.rd(ac[1]) 82 | print(" MSG", p.m.afmt(ac[1]), p.m.afmt(w)) 83 | for j in range(0,4): 84 | try: 85 | const.word(p, w + j) 86 | except: 87 | pass 88 | try: 89 | ww = p.m.rd(w + 2) 90 | q = p.m.rdqual(w + 2) 91 | if q == 3 and ww != 0: 92 | const.dot_txt(p, ww >> 1) 93 | except: 94 | pass 95 | 96 | if ac[2] != None: 97 | w = p.m.rd(ac[2]) 98 | print(" DST", p.m.afmt(ac[2]), p.m.afmt(w)) 99 | try: 100 | const.dot_txt(p, w, w + 3) 101 | except: 102 | pass 103 | 104 | if ins.mne[:3] == "OUT" or ins.mne == "OPEN": 105 | if ac[2] != None: 106 | z = p.m.rd(ac[2]) 107 | if z in did: 108 | continue 109 | did[z] = True 110 | print(" ZONE", p.m.afmt(z)) 111 | p.todo(z, desc.zonedesc) 112 | if ins.mne == "OUTTEXT": 113 | if ac[0] != None: 114 | t = p.m.rd(ac[0]) 115 | if t in did: 116 | continue 117 | did[t] = True 118 | if t != 0: 119 | t = t >> 1 120 | print(" TXT", 121 | p.m.afmt(ac[0]), p.m.afmt(t)) 122 | try: 123 | const.dot_txt(p, t) 124 | except: 125 | pass 126 | 127 | 128 | def hint(p): 129 | p.m.hex = True 130 | cpu = p.c["domus"] 131 | 132 | #p.todo(0o20550, cpu.disass) 133 | #p.todo(0o14341, cpu.disass) 134 | desc.zonedesc(p, 0o11634) 135 | x = p.t.add(0o012461, 0o012474, "Func") 136 | x = p.t.add(0o012474, 0o012477, "Func") 137 | x = p.t.add(0o012477, 0o012512, "Func") 138 | x = p.t.add(0o013272, 0o013303, "Func") 139 | 140 | const.dot_txt(p, 0o012517, None) 141 | 142 | def do_list(p, a, nw, fn = None): 143 | while a != 0: 144 | x = p.t.add(a - 4, a + nw, "XXXTBL") 145 | const.dot_txt(p, a - 4, a) 146 | if fn != None: 147 | fn(p, a) 148 | else: 149 | for i in range(0,nw): 150 | const.word(p, a + i, "%o") 151 | a = p.m.rd(a) 152 | 153 | do_list(p, 0o016451, 2) 154 | 155 | def fsym(p, a): 156 | l = list() 157 | for i in range(0, 4): 158 | l.append(const.word(p, a + i, "%o")) 159 | l[3].lcmt(str(domus.inter.inter.intins[p.m.rd(a + 3)][1:])) 160 | 161 | 162 | do_list(p, 0o026100, 4) 163 | do_list(p, 0o026270, 4, fsym) 164 | 165 | for a in range(0o015673, 0o015706): 166 | p.todo(p.m.rd(a), cpu.disass) 167 | 168 | 169 | def c12524(p, a): 170 | const.word(p, a + 3) 171 | cpu.disass(p.m.rd(a + 3)) 172 | follow_chain(p, 0o12524, c12524) 173 | 174 | def c13055(p, a): 175 | const.word(p, a + 0) 176 | const.word(p, a + 1) 177 | const.word(p, a + 3) 178 | const.word(p, a + 7) 179 | follow_chain(p, 0o13055, c13055) 180 | 181 | # calls to 20574' 182 | p.todo(0o20716, cpu.disass) 183 | p.todo(0o14600, cpu.disass) 184 | 185 | p.todo(0o17343, cpu.disass) 186 | 187 | p.todo(0o17341, cpu.disass) 188 | p.todo(0o015271, cpu.disass) 189 | 190 | p.run() 191 | 192 | hunt_outtext(p, cpu) 193 | -------------------------------------------------------------------------------- /domus/hints/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /domus/inter/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /domus/inter/lib.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # When we disassemble "INTER" programs, we run into calls to code procedures. 4 | # We need to divine which arguments these take, in order to proceed correctly. 5 | # 6 | # This file encapsulates this mess. 7 | 8 | def pure_guess(p, inter, ins, arg): 9 | """ 10 | Simply tally up TAKEV and TAKEA calls in what we think 11 | is the code-procedure body. This works surprisingly well. 12 | """ 13 | proc = p.a['procdesc'] 14 | amax = proc - inter.gc_max 15 | a0 = p.m.rd(proc - arg) 16 | for i in range(1, inter.gc_max): 17 | if i == arg: 18 | continue 19 | ax = p.m.rd(proc -i) 20 | if ax < amax and ax > a0: 21 | amax = ax 22 | l = list() 23 | for i in range(a0, amax): 24 | v = p.m.rdqual(i) 25 | if v != 1: 26 | continue 27 | v = p.m.rd(i) 28 | if v == 0o006236: 29 | l.append("A") 30 | elif v == 0o006237: 31 | l.append("V") 32 | elif v == 0o002235: 33 | break 34 | print("Pure Guess: Codeproc %d:" % arg) 35 | print(" ", p.m.afmt(a0), "...", p.m.afmt(amax)) 36 | print(" ", l) 37 | return l 38 | 39 | def ident_gc(p, inter, ins, arg): 40 | print("IGC", arg, ins) 41 | if arg > inter.gc_max: 42 | inter.gc_max = arg 43 | l = pure_guess(p, inter, ins, arg) 44 | return l 45 | -------------------------------------------------------------------------------- /domus/libs.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Try to recognize which CODEPROCEDURES have been linked into a program 4 | # by matching against preloaded domus libraries. We built a dictionary 5 | # tree of position independent information and walk that. 6 | 7 | import domus.mem 8 | import domus.reloc_file 9 | 10 | def sign(m, off, adr): 11 | q = m.rdqual(adr) 12 | d = m.rd(adr) 13 | if q == 2: 14 | d -= off 15 | if q == 3: 16 | d -= 2 * off 17 | return "%04x%d," % (d, q) 18 | 19 | class libs(object): 20 | def __init__(self, prefix = None, filenames = None): 21 | if prefix == None: 22 | prefix = "/rdonly/DDHF/oldcritter/DDHF/DDHF/RC3600/Sw/Rc3600/rc3600/__/__." 23 | if filenames == None: 24 | filenames = list() 25 | filenames.append("CODEP") 26 | filenames.append("CODEX") 27 | filenames.append("ULIB") 28 | filenames.append("FSLIB") 29 | self.t = dict() 30 | self.filenames = filenames 31 | self.prefix = prefix 32 | self.loaded = False 33 | 34 | 35 | def load(self, prefix, filename): 36 | f = domus.reloc_file.reloc_file(prefix + filename) 37 | for obj in f.build_index(): 38 | m = domus.mem.mem_domus() 39 | f.load(m, obj, silent=True) 40 | ln = 1 + f.max_nrel - f.min_nrel 41 | lz = 1 + f.max_zrel - f.min_zrel 42 | assert lz == 0 43 | t = self.t 44 | for i in range(f.min_nrel, f.max_nrel + 1): 45 | s = sign(m, f.min_nrel, i) 46 | if not s in t: 47 | t[s] = dict() 48 | t = t[s] 49 | if not 'Z' in t: 50 | t['Z'] = list() 51 | t['Z'].append(filename + "::" + obj) 52 | 53 | def match(self, tmem, tadr): 54 | if not self.loaded: 55 | for fn in self.filenames: 56 | try: 57 | self.load(self.prefix, fn) 58 | except: 59 | pass 60 | self.loaded = True 61 | t = self.t 62 | adr = tadr 63 | while True: 64 | s = sign(tmem, tadr, adr) 65 | if not s in t: 66 | return None 67 | t = t[s] 68 | if 'Z' in t: 69 | return (tadr, adr, t['Z']) 70 | adr += 1 71 | 72 | 73 | if __name__ == "__main__": 74 | dl = libs() 75 | -------------------------------------------------------------------------------- /domus/mem.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | import mem 7 | 8 | class mem_domus(mem.base_mem): 9 | def __init__(self, start = 0, end = 0x10000): 10 | mem.base_mem.__init__(self, start, end, 16, 3, True) 11 | self.qchar= ("0", " ", "'", '"', 'x', 'y', 'z', '*') 12 | self.hex = False 13 | 14 | def dfmt(self, d, w = True): 15 | if self.hex and w: 16 | return "%04x" % d 17 | elif self.hex: 18 | return "%x" % d 19 | elif w: 20 | return "%06o" % d 21 | else: 22 | return "%o" % d 23 | 24 | def aqfmt(self, a, q): 25 | if self.hex: 26 | fmt = "%04x" 27 | else: 28 | fmt = "%06o" 29 | 30 | if q == 3: 31 | s = fmt % (a >> 1) + self.qchar[2] + "*2" 32 | if a & 1: 33 | s += "+1" 34 | else: 35 | s = fmt % a + self.qchar[q] 36 | return s 37 | 38 | def afmt(self, a): 39 | if a < 0x1000: 40 | return self.aqfmt(a, 1) 41 | elif a < 0x8000: 42 | return self.aqfmt(a, 2) 43 | else: 44 | return self.aqfmt(a, 7) 45 | 46 | def qfmt(self, q): 47 | return self.qchar[q] 48 | 49 | # adr/data/ascii column formatter 50 | # returns a list of lines, all the same width 51 | def col1(self, p, start, end, lvl): 52 | l = list() 53 | while start < end: 54 | try: 55 | x = self.rd(start) 56 | q = self.rdqual(start) 57 | except: 58 | l.append(self.afmt(start) + " --") 59 | start += 1 60 | continue 61 | s = self.afmt(start) + " " + self.dfmt(x) 62 | if self.qualifiers > 0: 63 | s += self.qfmt(q) 64 | s += " |" 65 | for b in range(24,-1,-8): 66 | if self.bits > b: 67 | if q == 1: 68 | s += mem.ascii(x >> b) 69 | else: 70 | s += " " 71 | s += "|\t" 72 | l.append(s) 73 | start += 1 74 | return l 75 | 76 | # Default content formatter 77 | def col2(self, p, start, end, lvl): 78 | l = list() 79 | while start < end: 80 | q = p.m.rdqual(start) 81 | d = p.m.rd(start) 82 | s = ".XXX" 83 | if q == 3: 84 | s += "\t" + self.aqfmt(d, q) 85 | l.append(s) 86 | start += 1 87 | return l 88 | 89 | -------------------------------------------------------------------------------- /domus/rd_mupar.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Read MUPAR file and emit two files with special instructions and 4 | # page zero symbols 5 | # 6 | 7 | from __future__ import print_function 8 | 9 | fi = open("/rdonly/DDHF/oldcritter/DDHF/DDHF/RC3600/Sw/Rc3600/rcsrc/MUPAR", "r") 10 | 11 | loc = -1 12 | syms = dict() 13 | tsyms = dict() 14 | vsyms = dict() 15 | 16 | def subexpr(x): 17 | v = 0 18 | #print("SUBEXPR:", x) 19 | while len(x) > 0: 20 | if x[0].isspace(): 21 | x = x[1:] 22 | continue 23 | if x[:4] == "JSR@": 24 | v = 0x0c00 25 | x,s = subexpr(x[4:]) 26 | v |= s 27 | continue 28 | if x[:4] == "JMP@": 29 | v = 0x0400 30 | x,s = subexpr(x[4:]) 31 | v |= s 32 | continue 33 | if x[:1] == "@": 34 | v = 0x8000 35 | x,s = subexpr(x[1:]) 36 | v |= s 37 | continue 38 | if x[0].isdigit(): 39 | v *= 10 40 | v += int(x[0]) 41 | x = x[1:] 42 | elif x[0] == "+": 43 | x,s = subexpr(x[1:]) 44 | v += s 45 | elif x[0] == "-": 46 | x,s = subexpr(x[1:]) 47 | v -= s 48 | else: 49 | for i in range(0, len(x)): 50 | c = x[i] 51 | if c.isupper() or \ 52 | (i > 0 and c.isdigit()) or \ 53 | c == "." or c == "_" or c == "?": 54 | pass 55 | else: 56 | break 57 | if i + 1 == len(x): 58 | i += 1 59 | break 60 | j = i 61 | if j > 5: 62 | j = 5 63 | if x[:j] in tsyms: 64 | assert v == 0 65 | v = tsyms[x[:j]] 66 | x = x[i:] 67 | else: 68 | print("???", x) 69 | x = x[1:] 70 | exit(2) 71 | return (x, v) 72 | 73 | def expr(x): 74 | y,v = subexpr(x) 75 | assert y == "" 76 | #print("EXPR <%s> = %o" % (x, v)) 77 | return v 78 | 79 | for i in fi.readlines(): 80 | j = i.find(';') 81 | if j != -1: 82 | i = i[:j] 83 | i = i.strip() 84 | if i == "": 85 | continue 86 | j = i.split(None, 1) 87 | if j[0] == ".TITL": 88 | assert j[1] == "MUPAR" 89 | elif j[0] == ".RDX": 90 | rdx = int(j[1]) 91 | assert rdx == 10 92 | elif j[0] == ".END": 93 | break 94 | elif j[0] == ".LOC": 95 | # We mark definitions based on .loc directives with 0x10000 96 | tsyms["."] = expr(j[1]) | 0x10000 97 | elif j[0] == ".DUSR": 98 | (sym,exp) = j[1].split('=', 1) 99 | sym = sym.strip() 100 | exp = exp.strip() 101 | assert sym not in syms 102 | v = expr(exp) 103 | syms[sym] = v 104 | tsyms[sym[:5]] = v 105 | if v not in vsyms: 106 | vsyms[v] = sym 107 | #print("SYM[%s]=%06o" % (sym,v)) 108 | else: 109 | print(j) 110 | exit (2) 111 | fi.close() 112 | 113 | fof = open("domus_funcs.txt", "w") 114 | fopz = open("domus_page_zero.txt", "w") 115 | for f in (fof, fopz): 116 | f.write("# Machine generated file, see rd_mupar.py\n\n") 117 | 118 | ############################################################################# 119 | # Manual fixups 120 | 121 | vsyms[0x10020] = "CUR" 122 | vsyms[0x10000 | 0o02234] = "CNEXTINTER" 123 | vsyms[0x10000 | 0o02235] = "NEXTINTER" 124 | vsyms[0x10000 | 0o06236] = "TAKEA" 125 | vsyms[0x10000 | 0o06237] = "TAKEV" 126 | 127 | vsyms[0x10000 | 0o00227] = "RINTGIVEUP" 128 | vsyms[0x10000 | 0o00231] = "RINTBREAK" 129 | vsyms[0x10000 | 0o00240] = "PINTGIVEUP" 130 | vsyms[0x10000 | 0o00241] = "PRINTGIVEUP" 131 | 132 | ############################################################################# 133 | 134 | for i in sorted(vsyms.keys()): 135 | print("%05x %06o %s" % (i, i, vsyms[i])) 136 | if i >= 0x10000 and i <= 0x10100: 137 | fopz.write("%s 0x%04x\n" % (vsyms[i], i & 0xffff)) 138 | elif i >= 0x10400 and i < 0x11000: 139 | fof.write('%-20s "" ' % vsyms[i]) 140 | for j in range (15,-1,-1): 141 | fof.write("|%d" % ((i >> j) & 1)) 142 | fof.write("|\n") 143 | -------------------------------------------------------------------------------- /domus/reloc_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | import array 5 | 6 | class DomusFileError(Exception): 7 | def __init__(self, reason): 8 | self.reason = reason 9 | self.value = str(self.reason) 10 | def __str__(self): 11 | return repr(self.value) 12 | 13 | 14 | def radix40(y): 15 | s = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.?" 16 | v1 = y[0] 17 | v2 = y[1] 18 | l3 = v1 % 40 19 | l2 = int(v1 / 40) % 40 20 | l1 = int(v1 / (40*40)) % 40 21 | l5 = int(v2 / 32) % 40 22 | l4 = int(v2 / (40 * 32)) % 40 23 | #print(len(s), l1, l2, l3, l4, l5, s[l1], s[l2], s[l3], s[l4], s[l5]) 24 | return ((s[l1] + s[l2] + s[l3] + s[l4] + s[l5]).strip(), v2 & 0x1f) 25 | 26 | class reloc_file(object): 27 | def __init__(self, filename, skip = 0): 28 | # Read the entire file 29 | f = open(filename, "rb") 30 | if skip & 1: 31 | self.d = array.array("H", f.read()[skip:-1]) 32 | else: 33 | self.d = array.array("H", f.read()[skip:]) 34 | assert len(self.d) != 0 35 | self.filename = filename 36 | f.close() 37 | self.index = self.build_index() 38 | 39 | def build_index(self): 40 | # Builds index of objects in file 41 | l=dict() 42 | a = 0 43 | a0 = a 44 | nobj = 0 45 | titl = "OBJ%02d" % nobj 46 | while a < len(self.d): 47 | rec_typ = self.d[a] 48 | if rec_typ > 9: 49 | break 50 | if rec_typ == 0: 51 | a += 1 52 | a0 = a 53 | continue 54 | 55 | rec_len = self.d[a + 1] - 65536 56 | assert rec_len > -16 and rec_len < 0 57 | 58 | ss = 0 59 | for i in range (0, 6-rec_len): 60 | ss += self.d[a + i] 61 | ss &= 0xffff 62 | assert ss == 0 63 | 64 | a += 2 65 | 66 | # XXX: Check checksum 67 | 68 | a += 4 - rec_len 69 | 70 | if rec_typ == 7: 71 | titl = radix40(self.d[a0 + 6:a0+9])[0] 72 | if rec_typ == 6: 73 | l[titl] = (a0, a) 74 | nobj += 1 75 | titl = "OBJ%02d" % nobj 76 | a0 = a 77 | return l 78 | 79 | def load(self, mem, obj=None, off = 0x1000, offhi=0x8000, silent=False): 80 | if obj == None: 81 | if len(self.index) != 1: 82 | raise DomusFileError( 83 | "More than one object in file") 84 | for i in self.index: 85 | obj = i 86 | if obj not in self.index: 87 | raise DomusFileError( 88 | "Object not found in file:" + obj) 89 | if not silent: 90 | print("LOAD ", obj) 91 | self.rec_end = None 92 | self.rec_titl = None 93 | self.rec_size = None 94 | self.load_words = 0 95 | self.min_nrel = off 96 | self.max_nrel = off - 1 97 | self.min_zrel = offhi 98 | self.max_zrel = offhi - 1 99 | mem.load_order = list() 100 | a,ae = self.index[obj] 101 | while a < ae: 102 | rec_typ = self.d[a] 103 | rec_len = self.d[a + 1] - 65536 104 | s = "%d" % rec_typ 105 | s += " %3d" % rec_len 106 | rl = "" 107 | for i in range(2,5): 108 | r = "%05o" % (self.d[a + i] / 2) 109 | s += " " + r 110 | rl += r 111 | s += " %04x" % self.d[a + 5] 112 | y = list() 113 | z = list() 114 | for i in range(6, 6 - rec_len): 115 | x = self.d[a + i] 116 | z.append(int(rl[0])) 117 | if rl[0] == "0": 118 | s += " %04x " % x 119 | y.append(x) 120 | elif rl[0] == "1": 121 | s += " %04x " % x 122 | y.append(x) 123 | elif rl[0] == "2": 124 | s += " %04x'" % x 125 | y.append(x + off) 126 | elif rl[0] == "3": 127 | s += ' %04x"' % x 128 | y.append(x + off * 2) 129 | elif rl[0] == "7": 130 | s += " %04x*" % x 131 | y.append(x + offhi) 132 | else: 133 | raise DomusFileError( 134 | "Wrong Reloc %s" % rl[0]) 135 | rl = rl[1:] 136 | if rec_typ == 2: 137 | ax = y[0] 138 | mem.load_order.append((ax, ax + len(y) - 1)) 139 | for i in range(1, len(y)): 140 | if ax < offhi and ax > self.max_nrel: 141 | self.max_nrel = ax 142 | if ax >= offhi and ax > self.max_zrel: 143 | self.max_zrel = ax 144 | self.load_words += 1 145 | mem.setflags(ax, None, 146 | mem.can_read | mem.can_write, 147 | mem.invalid) 148 | mem.wr(ax, y[i] & 0xffff) 149 | mem.wrqual(ax, z[i]) 150 | ax += 1 151 | elif rec_typ == 6: 152 | if not silent: 153 | print("\t.END %o" % y[0]) 154 | self.rec_end = y[0] 155 | elif rec_typ == 7: 156 | self.rec_titl = radix40(y) 157 | if not silent: 158 | print("\t.TITL\t%s" % self.rec_titl[0]) 159 | elif rec_typ == 9: 160 | self.rec_size = y 161 | else: 162 | raise DomusFileError( 163 | "Load Unknown Record %d" % rec_typ) 164 | 165 | if not silent: 166 | print(s) 167 | a += 6 - rec_len 168 | 169 | if __name__ == "__main__": 170 | 171 | import mem 172 | 173 | dn="/rdonly/DDHF/oldcritter/DDHF/DDHF/RC3600/Sw/Rc3600/rc3600/__/" 174 | fn = dn + "__.MUM" 175 | fn = dn + "__.FSLIB" 176 | fn = dn + "__.ULIB" 177 | fn = dn + "__.CATLI" 178 | fn = dn + "__.PTP" 179 | fn = dn + "__.DOMAC" 180 | fn = dn + "__.DOMUS" 181 | 182 | fn = dn + "__.CATLI" 183 | 184 | df = reloc_file(fn) 185 | for i in df.index: 186 | print(i) 187 | m = mem.base_mem(0, 0x10000, 16, 3, True) 188 | df.load(m) 189 | print("END", df.rec_end) 190 | print("TITLE", df.rec_titl) 191 | print("HIMEM", df.rec_size) 192 | -------------------------------------------------------------------------------- /explore.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Various helper functions for explorations 4 | # 5 | 6 | #---------------------------------------------------------------------- 7 | # Check the python version 8 | 9 | import sys 10 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 11 | 12 | #---------------------------------------------------------------------- 13 | 14 | def gain(p, cpu, adr, follow_calls = True): 15 | """ 16 | How many instructions would we gain by starting disassembly at adr ? 17 | """ 18 | 19 | while p.run(): 20 | pass; 21 | 22 | ccpu = cpu.clone(follow_calls) 23 | 24 | ccpu.disass(adr) 25 | while p.run(): 26 | pass 27 | 28 | assert cpu.fails != None 29 | 30 | dx = dict() 31 | for i in ccpu.ins: 32 | 33 | # We only care for new stuff 34 | if i in cpu.ins: 35 | continue 36 | 37 | j = ccpu.ins[i] 38 | 39 | # If they are OK, we return them 40 | if j.status == "OK": 41 | dx[i] = j 42 | continue 43 | 44 | # If they failed, propagate up 45 | if j.status == "fail": 46 | j.disass = cpu 47 | cpu.ins[i] = j 48 | continue 49 | 50 | if ccpu.fails != 0: 51 | return None 52 | 53 | return dx 54 | 55 | def best_place_to_start(p, cpu, lo=None, hi=None): 56 | """ 57 | Try to find the instruction that causes most other instructions 58 | to be disassembled. 59 | 60 | Returns a list of (adr, #ins) tupples. 61 | """ 62 | 63 | while p.run(): 64 | pass; 65 | 66 | best = 0 67 | cand = None 68 | bdict = dict() 69 | 70 | lp = 0 71 | lx = list() 72 | for g in p.t.gaps(): 73 | g = list(g) 74 | if lo != None: 75 | if lo >= g[1]: 76 | continue 77 | if g[0] < lo: 78 | g[0] = lo 79 | if hi != None: 80 | if hi <= g[0]: 81 | continue 82 | if g[1] > hi: 83 | g[1] = hi 84 | i = g[0] 85 | while i < g[1]: 86 | if i >> 12 != lp: 87 | print("..." + p.m.afmt(i), "cands:", len(lx)) 88 | lp = i >> 12 89 | if i in cpu.ins: 90 | i = cpu.ins[i].hi 91 | continue 92 | if cpu.bm.tst(i): 93 | i += 1 94 | continue 95 | if i in bdict: 96 | i = bdict[i].hi 97 | continue 98 | xx = True 99 | this = gain(p, cpu, i, xx) 100 | if this == None: 101 | xx = False 102 | this = gain(p, cpu, i, xx) 103 | if this != None: 104 | l = len(this) 105 | if l > 0: 106 | lx.append((i,l, xx)) 107 | if l > best: 108 | print("Best so far: ", p.m.afmt(i), l) 109 | sys.stdout.flush() 110 | best = l 111 | cand = i 112 | bdict =this 113 | i += 1 114 | lx = sorted(lx, key=lambda x: -x[1]) 115 | return lx 116 | 117 | #---------------------------------------------------------------------- 118 | # 119 | 120 | def brute_force(p, cpu, lo=None, hi=None, max = None): 121 | """ 122 | Disassemble as much as possible, with as few pivot points as 123 | possible. Pivot instructions are marked with a lcmt. 124 | """ 125 | n = 0 126 | 127 | lx = best_place_to_start(p, cpu, lo, hi) 128 | if len(lx) == 0: 129 | return 130 | 131 | cand = lx[0][0] 132 | j = lx[0][1] 133 | 134 | while True: 135 | print("Doing", p.m.afmt(cand), "gain", j, "list", len(lx)) 136 | x = cpu.disass(cand) 137 | x.lcmt("<==== Brute Force Discovery #%d" % n) 138 | while p.run(): 139 | pass; 140 | n += 1 141 | if max != None and n >= max: 142 | break 143 | 144 | lx = sorted(lx, key=lambda x: -x[1]) 145 | best = 0 146 | cand = None 147 | ly = list() 148 | for j in lx: 149 | i,n,k = j 150 | if n <= best: 151 | ly.append(j) 152 | continue 153 | this = gain(p, cpu, i) 154 | if this == None: 155 | continue 156 | l = len(this) 157 | if l <= 0: 158 | continue 159 | ly.append((i,l, None)) 160 | if l > best: 161 | best = l 162 | cand = i 163 | if cand == None: 164 | break 165 | lx = ly 166 | j = best 167 | 168 | -------------------------------------------------------------------------------- /instree.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | from disass import DisassError 7 | 8 | ####################################################################### 9 | # Parse a "([01x] )*[01x]" string into a mask + bits 10 | 11 | def parse_match(bit, f): 12 | mask = 0 13 | bits = 0 14 | width = 0 15 | l = len(f) 16 | if l & 1 == 0: 17 | return None 18 | i = 0 19 | while i < l: 20 | mask <<= 1 21 | bits <<= 1 22 | width += 1 23 | if f[i] == "0": 24 | mask |= 1 25 | elif f[i] == "1": 26 | mask |= 1 27 | bits |= 1 28 | elif f[i] == "x": 29 | pass 30 | else: 31 | return None 32 | i += 1 33 | if i < l and f[i] != " ": 34 | return None 35 | i += 1 36 | return (bit, width, mask, bits) 37 | 38 | ####################################################################### 39 | # A single line from the specification 40 | 41 | class insline(object): 42 | def __init__(self, line, width = 8): 43 | self.mask = list() 44 | self.bits = list() 45 | self.flds = dict() 46 | 47 | #print("\n" + line) 48 | s = line.expandtabs().split("|") 49 | self.spec = s[0].split() 50 | b = 0 51 | l1 = list() 52 | l2 = list() 53 | for i in s[1:]: 54 | if i == "": 55 | continue 56 | f = parse_match(b, i) 57 | if f != None: 58 | l1.append(f) 59 | else: 60 | if len(i) & 1 == 0: 61 | print( 62 | "Error: Field has half bit:\n" + 63 | " %s\n" % line, 64 | " '%s'" % i) 65 | assert False 66 | w = (len(i) + 1) >> 1 67 | f = (b, w, i.strip()) 68 | l2.append(f) 69 | b += f[1] 70 | 71 | if b % width != 0: 72 | print( 73 | ("Error: %d not an multiple of %d bits.\n" + 74 | " %s") % (b, width, line)) 75 | assert False 76 | 77 | self.width = b 78 | for i in range(0, int(b/width)): 79 | self.mask.append(0) 80 | self.bits.append(0) 81 | 82 | # Convert match fields to mask/bits 83 | # XXX: there must be a cleaner way... 84 | for i in l1: 85 | s = i[1] - 1 86 | for b in range(i[0], i[0] + i[1]): 87 | j = int(b / width) 88 | r = b % width + 1 89 | if i[2] & (1 << s): 90 | self.mask[j] |= 1 << (width - r) 91 | if i[3] & (1 << s): 92 | self.bits[j] |= 1 << (width - r) 93 | s -= 1 94 | assert s == -1 95 | 96 | #print(line) 97 | for i in l2: 98 | b = i[0] 99 | w = i[1] 100 | e = b + w - 1 101 | if int(b / width) != int(e / width): 102 | print( 103 | "Error: Field %s spans " % i[2] + 104 | "%d-bit units:\n" % self.width + 105 | " %s\n" % line) 106 | assert False 107 | s = int(b / width) 108 | b -= s * width 109 | e -= s * width 110 | m = (1<> x[1]) & x[2] 120 | #print(p, adr, func, name, x, "\n", self.line, "0x%x" % v) 121 | return v 122 | 123 | 124 | def __repr__(self): 125 | s = "w%d <" % self.width 126 | t = "" 127 | for i in self.spec: 128 | s += t + i 129 | t = " " 130 | s += "> <" 131 | t = "" 132 | for i in range(0, len(self.mask)): 133 | s += t + "%02x|%02x" % (self.mask[i], self.bits[i]) 134 | t = ", " 135 | s += "> <" 136 | t = "" 137 | for i in self.flds: 138 | s += t + i 139 | t = ", " 140 | s += ">" 141 | return s 142 | 143 | ####################################################################### 144 | # Branch-point 145 | 146 | class insbranch(object): 147 | def __init__(self, lvl): 148 | self.lvl = lvl 149 | self.spec = list() 150 | 151 | def insert(self, x): 152 | #print(">>", x) 153 | m = x.mask[self.lvl] 154 | b = x.bits[self.lvl] 155 | for i in self.spec: 156 | if m != i[0]: 157 | continue 158 | if b in i[1]: 159 | if type(i[1][b]) == insbranch: 160 | i[1][b].insert(x) 161 | return 162 | if len(x.mask) > self.lvl + 1 or \ 163 | len(i[1][b].mask) > self.lvl + 1: 164 | y = insbranch(self.lvl + 1) 165 | y.insert(i[1][b]) 166 | y.insert(x) 167 | i[1][b] = y 168 | return 169 | else: 170 | print("Error: Collision") 171 | print(x) 172 | print(i[1][b]) 173 | assert False 174 | if self.lvl + 1 == len(x.mask): 175 | i[1][b] = x 176 | else: 177 | y = insbranch(self.lvl + 1) 178 | y.insert(x) 179 | i[1][b] = y 180 | return 181 | l = list() 182 | l.append(m) 183 | l.append(dict()) 184 | if self.lvl + 1 == len(x.mask): 185 | l[1][b] = x 186 | else: 187 | y = insbranch(self.lvl + 1) 188 | y.insert(x) 189 | l[1][b] = y 190 | for j in range(0, len(self.spec)): 191 | i = self.spec[j] 192 | if ~(m & i[0]) & m: 193 | self.spec.insert(j, l) 194 | return 195 | self.spec.append(l) 196 | 197 | def __repr__(self): 198 | return "" % self.lvl 199 | 200 | def print(self): 201 | f = "" 202 | for i in range(0, self.lvl): 203 | f += " " 204 | for i in self.spec: 205 | print(f + " & %04x" % i[0]) 206 | for j in sorted(i[1].keys()): 207 | if type(i[1][j]) == insbranch: 208 | print(f + " %04x" % j) 209 | i[1][j].print() 210 | else: 211 | print(f + " %04x " % j, i[1][j]) 212 | 213 | def find(self, v): 214 | for i in self.spec: 215 | b = v & i[0] 216 | if b in i[1]: 217 | return i[1][b] 218 | return None 219 | 220 | def addone(self, l, y): 221 | # Only add if the new entry is not a proper subset of 222 | # of an already existing entry. 223 | for j in l: 224 | x = False 225 | for k in range(0, len(j.mask)): 226 | if k >= len(y.mask): 227 | break 228 | if y.mask[k] & j.mask[k] != y.mask[k]: 229 | x = True 230 | if not x: 231 | return 232 | l.append(y) 233 | 234 | def allfind(self, adr, func, incr, l): 235 | v = func(adr) 236 | for i in self.spec: 237 | b = v & i[0] 238 | if not b in i[1]: 239 | continue 240 | y = i[1][b] 241 | if type(y) == insbranch: 242 | y.allfind(adr + incr, func, incr, l) 243 | else: 244 | self.addone(l, y) 245 | return l 246 | 247 | ####################################################################### 248 | # 249 | 250 | class instree(object): 251 | def __init__(self, width=8, filename=None): 252 | self.width = width 253 | self.root = insbranch(0) 254 | if filename != None: 255 | self.load(filename) 256 | 257 | def load(self, filename): 258 | fi = open(filename, "r") 259 | for i in fi.readlines(): 260 | i = i.strip() 261 | if i == "" or i[0] == "#": 262 | continue 263 | x = insline(i, self.width) 264 | self.root.insert(x) 265 | fi.close() 266 | 267 | def load_string(self, s): 268 | for i in s.split("\n"): 269 | i = i.strip() 270 | if i == "" or i[0] == "#": 271 | continue 272 | x = insline(i, self.width) 273 | self.root.insert(x) 274 | 275 | def print(self): 276 | self.root.print() 277 | 278 | def find(self, p, adr, func, incr = None): 279 | if incr == None: 280 | incr = self.width >> 3 281 | r = self.root 282 | for i in range(0,10, incr): 283 | b = func(adr + i) 284 | r = r.find(b) 285 | if type(r) != insbranch: 286 | break 287 | if r == None: 288 | raise DisassError("no matching ins") 289 | return r 290 | 291 | # This finds all non-overlapping candidates. 292 | # such as mask=0xf002 and mask=0xf001 293 | # but not mask=0xf001 and mask=0xf000 294 | def allfind(self, p, adr, func, incr = None): 295 | l = list() 296 | if incr == None: 297 | incr = self.width >> 3 298 | self.root.allfind(adr, func, incr, l) 299 | return l 300 | 301 | if __name__ == "__main__": 302 | it = instree(8, "cpus/mcs51_instructions.txt") 303 | it.print() 304 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.2 2 | # 3 | # A list-based language to model instructions. 4 | # 5 | # Values are a tuple of (width, value) where value can be None if 6 | # it is unknown, and False if it is unused. 7 | # 8 | # Syntax: 9 | # ( Verb, arg, ...) 10 | # "#0b..." binary constant, number of bits given sets width 11 | # "#0x..." hex constant, number of nybbles given sets width 12 | # "/..." register 13 | 14 | import random 15 | 16 | class ModelError(Exception): 17 | def __init__(self, reason): 18 | self.reason = reason 19 | self.value = str(self.reason) 20 | def __str__(self): 21 | return repr(self.value) 22 | 23 | 24 | class model(object): 25 | def __init__(self): 26 | self.verbs = { 27 | "SEQ": (self.verb_seq, "..."), 28 | ">>": (self.verb_right_shift, "val", "bits"), 29 | "<<": (self.verb_left_shift, "val", "bits" "[bi]" "[bo]"), 30 | "+": (self.verb_add, "val", "val" "[ci]" "[co]"), 31 | "-": (self.verb_sub, "val", "val" "[bi]" "[bo]"), 32 | "=": (self.verb_assign, "dest", "val"), 33 | "AND": (self.verb_and, "val1", "val2"), 34 | "OR": (self.verb_or, "val1", "val2"), 35 | "RND": (self.verb_rnd, None), 36 | "XOR": (self.verb_xor, "val1", "val2"), 37 | "INC": (self.verb_increment, "val", "[bits]"), 38 | "DEC": (self.verb_decrement, "val", "[bits]"), 39 | "TRIM": (self.verb_trim, "val", "bits"), 40 | "ZERO?": (self.verb_zero, "val", "cond1", "cond2"), 41 | } 42 | 43 | def setreg(self, p, state, reg, val): 44 | if not reg in state: 45 | raise ModelError("Set: register %s not in state" % reg) 46 | if state[reg][0] != val[0]: 47 | raise ModelError("Setting wrong width %d should be %d" 48 | % (val[0], state[reg][0])) 49 | state[reg] = val 50 | 51 | def getreg(self, p, state, reg): 52 | if not reg in state: 53 | raise ModelError("Get: register %s not in state" % reg) 54 | return state[reg] 55 | 56 | def getint(self, p, state, val): 57 | assert type(val) == str 58 | w = 0 59 | v = 0 60 | if val[:3] == "#0b": 61 | for i in val[3:]: 62 | v <<= 1 63 | w += 1 64 | if i >= '0' and i <= '1': 65 | v |= int(i) 66 | else: 67 | raise ModelError( 68 | "Int: Illegal binary: %s" % val) 69 | elif val[:3] == "#0x": 70 | for i in val[3:]: 71 | v <<= 4 72 | w += 4 73 | try: 74 | v |= int(i, 16) 75 | except: 76 | raise ModelError( 77 | "Int: Illegal octal: %s" % val) 78 | else: 79 | raise ModelError("Int: Illegal integer: %s" % val) 80 | return (w,v) 81 | 82 | def eval(self, p, state, expr): 83 | #print("Eval:", expr) 84 | #print(" State:", state) 85 | if state == None: 86 | return None 87 | 88 | if type(expr) == str and expr[0] == "/": 89 | retval = self.getreg(p, state, expr); 90 | elif type(expr) == str and expr[0] == "#": 91 | retval = self.getint(p, state, expr); 92 | elif type(expr) == tuple and expr[0] in self.verbs: 93 | x = self.verbs[expr[0]] 94 | if x[1] == None: 95 | retval = x[0](p, state, expr) 96 | elif len(x) == len(expr): 97 | retval = x[0](p, state, expr) 98 | elif len(x) <= len(expr) and x[-1] == "...": 99 | retval = x[0](p, state, expr) 100 | else: 101 | for i in range(1,len(x)): 102 | if x[i][0] == "[": 103 | break; 104 | if len(expr) < i + 1: 105 | raise ModelError("Syntax: arg_count:" + str(expr)) 106 | retval = x[0](p, state, expr) 107 | elif type(expr) == tuple and not expr[0] in self.verbs: 108 | raise ModelError("Unknown verb" + str(expr[0])) 109 | else: 110 | raise ModelError("Unknown expression" + str(expr)) 111 | 112 | #print(" Return(", expr, "):", retval) 113 | return retval 114 | 115 | def verb_seq(self, p, state, expr): 116 | for i in expr[1:]: 117 | self.eval(p, state, i) 118 | 119 | def verb_right_shift(self, p, state, expr): 120 | v1 = self.eval(p, state, expr[1]) 121 | if v1[1] == None: 122 | return v1 123 | if len(expr) > 2: 124 | v2 = self.eval(p, state, expr[2]) 125 | else: 126 | v2 = (8, 1) 127 | if v2[1] == None: 128 | raise ModelError("Verb: >> BITS unknown") 129 | return (v1[0], v1[1] >> v2[1]) 130 | 131 | def verb_left_shift(self, p, state, expr): 132 | v1 = self.eval(p, state, expr[1]) 133 | if v1[1] == None: 134 | return v1 135 | 136 | if len(expr) > 2: 137 | v2 = self.eval(p, state, expr[2]) 138 | else: 139 | v2 = (8, 1) 140 | if v2[1] == None: 141 | raise ModelError("Verb: << BITS unknown") 142 | 143 | return (v1[0], v1[1] << v2[1]) 144 | 145 | def verb_assign(self, p, state, expr): 146 | v2 = self.eval(p, state, expr[2]) 147 | self.setreg(p, state, expr[1], v2) 148 | 149 | def verb_increment(self, p, state, expr): 150 | if len(expr) > 2: 151 | v2 = self.eval(p, state, expr[2]) 152 | else: 153 | v2 = (8, 1) 154 | v1 = self.getreg(p, state, expr[1]) 155 | if v1[1] != None and v2[1] != None: 156 | vn = (v1[0], (v1[1] + v2[1]) & ((1 << v1[0]) - 1)) 157 | else: 158 | vn = (v1[0], None) 159 | self.setreg(p, state, expr[1], vn) 160 | return vn 161 | 162 | def verb_decrement(self, p, state, expr): 163 | if len(expr) > 2: 164 | v2 = self.eval(p, state, expr[2]) 165 | else: 166 | v2 = (8, 1) 167 | v1 = self.getreg(p, state, expr[1]) 168 | if v1[1] != None and v2[1] != None: 169 | vn = (v1[0], (v1[1] - v2[1]) & ((1 << v1[0]) - 1)) 170 | else: 171 | vn = (v1[0], None) 172 | self.setreg(p, state, expr[1], vn) 173 | return vn 174 | 175 | def verb_or(self, p, state, expr): 176 | v1 = self.eval(p, state, expr[1]) 177 | v2 = self.eval(p, state, expr[2]) 178 | assert v1[0] == v2[0] 179 | if v1[1] == None or v2[1] == None: 180 | return (v1[0], None) 181 | return (v1[0], v1[1] | v2[1]) 182 | 183 | def verb_xor(self, p, state, expr): 184 | v1 = self.eval(p, state, expr[1]) 185 | v2 = self.eval(p, state, expr[2]) 186 | assert v1[0] == v2[0] 187 | if v1[1] == None or v2[1] == None: 188 | return (v1[0], None) 189 | return (v1[0], v1[1] ^ v2[1]) 190 | 191 | def verb_and(self, p, state, expr): 192 | v1 = self.eval(p, state, expr[1]) 193 | v2 = self.eval(p, state, expr[2]) 194 | assert v1[0] == v2[0] 195 | if v1[1] == None or v2[1] == None: 196 | return (v1[0], None) 197 | return (v1[0], v1[1] & v2[1]) 198 | 199 | def verb_add(self, p, state, expr): 200 | v1 = self.eval(p, state, expr[1]) 201 | v2 = self.eval(p, state, expr[2]) 202 | assert v1[0] == v2[0] 203 | 204 | if len(expr) > 3: 205 | ci = self.eval(p, state, expr[3]) 206 | else: 207 | ci = (1,0) 208 | 209 | if v1[1] == None or v2[1] == None or ci[1] == None: 210 | if len(expr) > 4: 211 | self.setreg(p, state, expr[4], (1, None)) 212 | return (v1[0], None) 213 | 214 | s = v1[1] + v2[1] + ci[1] 215 | 216 | if len(expr) > 4: 217 | self.setreg(p, state, expr[4], (1, s >> v1[0])) 218 | 219 | return (v1[0], s & ((1 << v1[0]) - 1)) 220 | 221 | def verb_sub(self, p, state, expr): 222 | v1 = self.eval(p, state, expr[1]) 223 | v2 = self.eval(p, state, expr[2]) 224 | assert v1[0] == v2[0] 225 | 226 | if len(expr) > 3: 227 | bi = self.eval(p, state, expr[3]) 228 | else: 229 | bi = (1,0) 230 | 231 | if v1[1] == None or v2[1] == None or bi[1] == None: 232 | if len(expr) > 4: 233 | self.setreg(p, state, expr[4], (1, None)) 234 | return (v1[0], None) 235 | 236 | s = v1[1] - (v2[1] + bi) 237 | 238 | if len(expr) > 4: 239 | self.setreg(p, state, expr[4], (1, s >> v1[0])) 240 | 241 | return (v1[0], s & ((1 << v1[0]) - 1)) 242 | 243 | def verb_trim(self, p, state, expr): 244 | v1 = self.eval(p, state, expr[1]) 245 | v2 = self.eval(p, state, expr[2]) 246 | return(v2[1], v1[1] & ((1 << v2[1]) - 1)) 247 | 248 | def verb_zero(self, p, state, expr): 249 | v1 = self.eval(p, state, expr[1]) 250 | if v1[1] == 0: 251 | self.eval(p, state, expr[2]) 252 | elif v1[1] != None: 253 | self.eval(p, state, expr[3]) 254 | else: 255 | # XXX: what ? 256 | self.eval(p, state, expr[3]) 257 | 258 | def verb_rnd(self, p, state, expr): 259 | return (1, 1) 260 | if random.random() >= .5: 261 | return (1, 1) 262 | else: 263 | return (1, 0) 264 | 265 | if __name__ == "__main__": 266 | 267 | m = model() 268 | 269 | si = { 270 | "/R1": (16,0), 271 | } 272 | 273 | m.eval(None, si, "/R1") 274 | m.eval(None, si, ("SEQ", "#0b001", "#0x001")) 275 | m.eval(None, si, (">>", "#0b101", "#0x001")) 276 | m.eval(None, si, ("=", "/R1", "#0x0001")) 277 | print(si) 278 | m.eval(None, si, ("INC", "/R1")) 279 | print(si) 280 | m.eval(None, si, ("DEC", "/R1", "#0x3")) 281 | print(si) 282 | try: 283 | m.eval(None, si, ("DEC", "/R2", "#0x3")) 284 | assert(False) 285 | except: 286 | pass 287 | m.eval(None, si, ("DEC",)) 288 | -------------------------------------------------------------------------------- /notes: -------------------------------------------------------------------------------- 1 | Sun Mar 25 06:29:34 UTC 2012 2 | 3 | Pseudo-language, inspired by Halvar Flake BH 2004: 4 | 5 | (oper, src, dst) 6 | oper: 7 | string 8 | globale namespace 9 | per CPU pfx'ed by "cpu::" 10 | src: 11 | tuple 12 | dst: 13 | str -> register 14 | None -> no effects 15 | True -> side-effects 16 | 17 | A register cannot be a src if it is a dst. 18 | 19 | 20 | Sun Nov 27 18:08:19 UTC 2011 21 | Non-contig functions normal in M$ compiler output 22 | bh-asia-02-halvarflake.pdf 23 | 24 | Sun Nov 27 18:08:19 UTC 2011 25 | XXX: m68000 DBF instruction has no flow ? 26 | --------------- 27 | 28 | p -- pyreveng instance 29 | General container for a reverse engineering task, 30 | to make it possible to have multiple such in a 31 | single program program 32 | 33 | p::todo() 34 | A task-list facility for serializing 35 | work-points, rather than relying on deep 36 | recursion to track code. 37 | 38 | p::study() 39 | A facility for having code study partial 40 | results, attempting to divine or deduce 41 | further points of attack. 42 | 43 | p.m -- memory instance 44 | The bits we are working on. 45 | 46 | p.t -- tree instance 47 | A hierarchial dissection of the tree into component 48 | parts and structures. 49 | 50 | p.c[] -- array of disassemblers 51 | One image can contain multiple kinds of code to be 52 | disassembled, typically CPU instructions and some 53 | kind of interpreted bytecode. 54 | 55 | p.c[].g -- graph instance 56 | Flow-control resolution for particular language 57 | domain. 58 | 59 | r(p) -- renderer 60 | Formats or otherwise presents the completed 61 | reverse-engineering 62 | -------------------------------------------------------------------------------- /pyreveng.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is the central container-class for a PyRevEng job. 4 | # 5 | # Services rendered: 6 | # todo Todo list, things to do, one thing after another 7 | 8 | #---------------------------------------------------------------------- 9 | # Check the python version 10 | 11 | import sys 12 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 13 | 14 | #---------------------------------------------------------------------- 15 | # Python dist imports 16 | 17 | # PyRevEng imports 18 | import tree 19 | 20 | class pyreveng(object): 21 | def __init__(self, m, lo=None, hi=None): 22 | """ The container class for a reverse engineering task. 23 | 24 | m: 25 | A memory class 26 | lo: 27 | The lowest address of interest 28 | hi: 29 | The higest address of interest 30 | """ 31 | 32 | self.m = m 33 | self.lo = lo 34 | self.hi = hi 35 | if self.lo == None: 36 | self.lo = m.start 37 | if self.hi == None: 38 | self.hi = m.end 39 | assert type(self.lo) == int 40 | assert type(self.hi) == int 41 | 42 | self.t = tree.tree(self.lo, self.hi) 43 | 44 | self.c = dict() 45 | 46 | # @todo 47 | self.__tlist = list() 48 | 49 | # @label 50 | self.label = dict() 51 | 52 | # Random attributes 53 | self.a = dict() 54 | 55 | # @hints 56 | self.hints = dict() 57 | 58 | self.cmt_start = 56 59 | 60 | ############################################################### 61 | # HINT processing 62 | # 63 | def hint(self, adr): 64 | if not adr in self.hints: 65 | self.hints[adr] = dict() 66 | return self.hints[adr] 67 | 68 | ############################################################### 69 | # TODO list processing 70 | # 71 | 72 | def todo(self, adr, func, priv = None): 73 | assert type(adr) == int 74 | if adr < self.lo or adr > self.hi: 75 | if False: 76 | print("WARNING: Ignoring todo at " + 77 | self.m.afmt(adr), func, priv) 78 | return 79 | try: 80 | self.m.chkadr(adr) 81 | except: 82 | return 83 | self.__tlist.append((adr, func, priv)) 84 | 85 | def run(self): 86 | if len(self.__tlist) == 0: 87 | return False 88 | while len(self.__tlist) > 0: 89 | c = self.__tlist[0] 90 | del self.__tlist[0] 91 | if True: 92 | c[1](self, c[0], c[2]) 93 | return True 94 | try: 95 | c[1](self, c[0], c[2]) 96 | except: 97 | print("FAILED %x\n\t" % c[0], c[1], "\n\t", c[2]) 98 | try: 99 | print(c[2].debug()) 100 | except: 101 | pass 102 | 103 | return True 104 | 105 | ############################################################### 106 | 107 | def setlabel(self, a, lbl): 108 | self.label[a] = lbl 109 | 110 | ############################################################### 111 | # Load labels from file 112 | # 113 | 114 | def loadlabels(self, filename): 115 | fi = open(filename, "r") 116 | for i in fi.readlines(): 117 | i = i.strip() 118 | if i == "" or i[0] == "#": 119 | continue 120 | j = i.split() 121 | self.setlabel(int(j[1], 0), j[0]) 122 | fi.close() 123 | 124 | ############################################################### 125 | # A general purpose hexdumping routine 126 | # 127 | 128 | def hexdump(self, start = None, end = None, fo = sys.stdout, wid=16): 129 | if start == None: 130 | start = self.m.start 131 | 132 | if end == None: 133 | end = self.m.end 134 | 135 | # Must be power of two 136 | assert wid & (wid -1) == 0 137 | 138 | adr = start 139 | while adr < end: 140 | s = self.m.afmt(adr) 141 | s += " " 142 | t = "" 143 | b = adr & ~(wid -1) 144 | e = b + wid 145 | if e > end: 146 | e = end 147 | if self.m.tstflags(b, e, self.m.undef): 148 | adr = b + wid 149 | continue 150 | for i in range(0, wid): 151 | if i == 8: 152 | s += " " 153 | 154 | if i < (adr & (wid-1)) or b + i >= end: 155 | s += " .." 156 | t += "." 157 | continue 158 | try: 159 | x = self.m.rd(b + i) 160 | except: 161 | s += " --" 162 | t += "-" 163 | continue 164 | 165 | s += " %02x" % x 166 | if x >= 32 and x <= 126: 167 | t += "%c" % x 168 | else: 169 | t += "." 170 | s += " |" + t + "|\n" 171 | fo.write(s) 172 | adr = b + 16 173 | -------------------------------------------------------------------------------- /render.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | 4 | from __future__ import print_function 5 | 6 | # Python dist imports 7 | import sys 8 | import random 9 | 10 | # PyRevEng imports 11 | import tree 12 | 13 | class render(object): 14 | def __init__(self, p, lw=10, iw = 48, cw=32): 15 | self.p = p 16 | self.m = p.m 17 | self.t = p.t 18 | self.indent = "" 19 | self.gaps = 0 20 | # Label Width: 21 | self.lw = lw 22 | # Instruction Width: 23 | self.iw = iw 24 | # Comment Width: 25 | self.cw = cw 26 | 27 | # Block Cmt sep line 28 | 29 | s = ";" 30 | while len(s) < self.lw + self.iw + self.cw: 31 | s += "-" 32 | self.bcl = s + "\n" 33 | 34 | ############################################################### 35 | # Rendering 36 | # 37 | def __pad_to(self, r, w): 38 | while len(r.expandtabs()) <= w - 8: 39 | r += "\t" 40 | while len(r.expandtabs()) < w: 41 | r += " " 42 | return r 43 | 44 | def __fmt(self, fo, b, l, s, c): 45 | n = len(b) 46 | if len(l) > n: 47 | n = len(l) 48 | if len(s) > n: 49 | n = len(s) 50 | if len(c) > n: 51 | n = len(c) 52 | for i in range(0, n): 53 | ff = "" 54 | if i < len(b): 55 | ff += b[i].expandtabs() 56 | ff = ff.ljust(self.col1w) 57 | if i < len(l): 58 | ff += l[i].expandtabs() 59 | ff = ff.ljust(self.col1w + self.lw) 60 | if i < len(s): 61 | ff += s[i].expandtabs() 62 | ff = ff.ljust(self.col1w + self.lw + self.iw) 63 | if i < len(c): 64 | ff += "; " + c[i].expandtabs() 65 | fo.write(ff + "\n") 66 | 67 | def __render_xxx(self, start, end, fo, lvl): 68 | c1 = self.m.col1(self, start, end, lvl) 69 | c2 = self.m.col2(self, start, end, lvl) 70 | self.__fmt(fo, c1, (), c2, ()) 71 | self.gaps += end - start 72 | 73 | # 'xxx' render readable locations in this gap 74 | def __render_gaps(self, start, end, fo, lvl): 75 | if start == end: 76 | return 77 | s = False 78 | j = start 79 | while j < end: 80 | try: 81 | x = self.m.rd(j) 82 | if s == False: 83 | s = j 84 | j += 1 85 | except: 86 | if s != False: 87 | self.__render_xxx(s, j, fo, lvl) 88 | try: 89 | jj = self.m.next_adr(j) 90 | print("NA %x %x" % (j, jj)) 91 | j = jj 92 | except: 93 | j += 1 94 | s = False 95 | if s != False: 96 | self.__render_xxx(s, end, fo, lvl) 97 | 98 | # Render, recursively, one tree node 99 | def __render(self, t, lvl, fo): 100 | 101 | if t.fold and len(t.child) > 0: 102 | print("WARN: tree.fold has %d children" % len(t.child)) 103 | print("\t", t) 104 | t.fold = False 105 | t.render = None 106 | 107 | if t.render == None: 108 | fo.write("%s-%s %s\n" % ( 109 | self.m.afmt(t.start), self.m.afmt(t.end), t.tag)) 110 | 111 | if t.blockcmt != "": 112 | for i in t.blockcmt[:-1].split("\n"): 113 | if i == "-": 114 | fo.write(self.col1s + self.bcl) 115 | else: 116 | fo.write(self.col1s + "; " + i + "\n") 117 | 118 | if t.render == None: 119 | a = t.start 120 | for i in t.child: 121 | self.__render_gaps(a, i.start, fo, lvl) 122 | self.__render(i, lvl + 1, fo) 123 | a = i.end 124 | self.__render_gaps(a, t.end, fo, lvl) 125 | return 126 | 127 | if type(t.render) == str: 128 | s = t.render.split("\n") 129 | else: 130 | try: 131 | s = t.render(self.p, t) 132 | except: 133 | print("Render failed " + 134 | self.p.m.afmt(t.start), t.render) 135 | assert False 136 | 137 | b = self.m.col1(self, t.start, t.end, lvl) 138 | l = () 139 | if t.start in self.p.label: 140 | lx = self.p.label[t.start] 141 | if len(lx) + 2 < self.lw: 142 | l = (lx + ":",) 143 | else: 144 | ff = "".ljust(self.col1w) 145 | ff += lx + ":\n" 146 | fo.write(ff) 147 | c = t.cmt 148 | if t.fold: 149 | x = len(l) 150 | if len(s) > x: 151 | x = len(s) 152 | if len(c) > x: 153 | x = len(c) 154 | if x + 1 < len(b): 155 | b1 = b[0:x] 156 | #b1.append(b[-1]) 157 | b = b1 158 | 159 | self.__fmt(fo, b, l, s, c) 160 | 161 | def render(self, fname="-", start = None, end = None): 162 | 163 | if fname == "-": 164 | fo = sys.stdout 165 | else: 166 | fo = open(fname, "w") 167 | 168 | if start == None: 169 | start = self.m.start 170 | 171 | if end == None: 172 | end = self.m.end 173 | 174 | # XXX: do something with start & end 175 | 176 | # Calculate space string for non-col1 lines 177 | # XXX: hackish: 178 | 179 | xx = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 180 | for i in range (0,100): 181 | a = int(random.random() * (end - start) + start) 182 | try: 183 | a = self.m.next_adr(a) 184 | except: 185 | pass 186 | try: 187 | self.m.rd(a) 188 | xx = self.m.col1(self, a, a + 1, 0)[0] 189 | except: 190 | continue 191 | break 192 | self.col1w = len(xx.expandtabs()) 193 | self.col1s = self.__pad_to("", self.col1w) 194 | self.col1c = self.__pad_to("", self.p.cmt_start) 195 | 196 | self.__render(self.t, 0, fo) 197 | 198 | print("%d locations xxx'ed" % self.gaps) 199 | 200 | fo.close() 201 | 202 | #---------------------------------------------------------------------- 203 | def __addflow(self, t, priv=None, lvl=0): 204 | if not 'flow' in t.a: 205 | return 206 | s = "" 207 | for i in t.a['flow']: 208 | if s != "": 209 | s += " " 210 | if type(i[2]) == int: 211 | d = self.p.m.afmt(i[2]) 212 | else: 213 | d = str(i[2]) 214 | if i[0] == "cond": 215 | s += ">:" + i[1] + ":" + d 216 | elif i[0] == "call": 217 | s += "C:" + i[1] + ":" + d 218 | elif i[0] == "ret": 219 | s += "R:" + i[1] + ":" + d 220 | else: 221 | s += str(i) 222 | if len(s) > 40: 223 | t.cmt.append(s) 224 | s = "" 225 | 226 | if len(s) > 0: 227 | t.cmt.append(s) 228 | 229 | def add_flows(self): 230 | self.p.t.recurse(self.__addflow) 231 | -------------------------------------------------------------------------------- /tasks/cbm900/EPROM_C_900_boot-H_V_1.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/cbm900/EPROM_C_900_boot-H_V_1.0.bin -------------------------------------------------------------------------------- /tasks/cbm900/EPROM_C_900_boot-L_V_1.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/cbm900/EPROM_C_900_boot-L_V_1.0.bin -------------------------------------------------------------------------------- /tasks/cbm900_fd/EPROM_Z8000_Fl.Cont._S41_6-20-85.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/cbm900_fd/EPROM_Z8000_Fl.Cont._S41_6-20-85.bin -------------------------------------------------------------------------------- /tasks/cbm900_wdc/MCU_WDC_U10.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/cbm900_wdc/MCU_WDC_U10.bin -------------------------------------------------------------------------------- /tasks/cbm900_wdc/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a demo-task which disassembles the CBM900 disk controller MCU 4 | # 5 | 6 | ####################################################################### 7 | # Check the python version 8 | 9 | import sys 10 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 11 | 12 | ####################################################################### 13 | # Set up a search path to two levels below 14 | 15 | import os 16 | sys.path.insert(0, os.path.abspath(os.path.join(".", "..", ".."))) 17 | 18 | ####################################################################### 19 | # Stuff we need... 20 | import mem 21 | import const 22 | import pyreveng 23 | import render 24 | import topology 25 | import cpus.mcs48 26 | 27 | 28 | ####################################################################### 29 | # Set up the memory image 30 | m0 = mem.byte_mem(0, 0x001000, 0, True, "little-endian") 31 | 32 | m0.fromfile("MCU_WDC_U10.bin", 0x0000, 1) 33 | m0.bcols=2 34 | 35 | ####################################################################### 36 | # Create a pyreveng instance 37 | p = pyreveng.pyreveng(m0) 38 | 39 | ####################################################################### 40 | 41 | p.t.blockcmt += """- 42 | - 43 | """ 44 | 45 | 46 | const.fill(p, mid=0x004) 47 | const.fill(p, mid=0x008) 48 | const.fill(p, mid=0x4b0) 49 | const.fill(p, mid=0x0f3) 50 | const.fill(p, mid=0x1f5) 51 | const.fill(p, mid=0x2fb) 52 | const.fill(p, mid=0x3f1) 53 | const.fill(p, lo=0x5f5) 54 | const.fill(p, mid=0x6fb) 55 | const.fill(p, mid=0x7ed) 56 | 57 | ####################################################################### 58 | cpu = cpus.mcs48.mcs48(p) 59 | 60 | ####################################################################### 61 | 62 | # vectors 63 | cpu.disass(0) 64 | cpu.disass(3) 65 | cpu.disass(7) 66 | 67 | ####################################################################### 68 | 69 | while p.run(): 70 | pass 71 | 72 | ####################################################################### 73 | # Jump table 74 | 75 | j = cpu.disass(0x3f) 76 | for i in range(0x0a,0x21): 77 | v = p.m.rd(i) 78 | const.byte(p, i) 79 | cpu.disass(v) 80 | j.flow("cond", "x", v) 81 | p.setlabel(v, "CMD_%02x" % (i - 0xa)) 82 | 83 | ####################################################################### 84 | # No idea... 85 | 86 | for i in range(0x000,0x800,0x100): 87 | cpu.disass(i + 0xfe) 88 | 89 | ####################################################################### 90 | # Pure guess 91 | 92 | const.txt(p, 0x5ae) 93 | cpu.disass(0x695) 94 | cpu.disass(0x700) 95 | cpu.disass(0x70d) 96 | cpu.disass(0x720) 97 | ####################################################################### 98 | 99 | import explore 100 | #import cProfile 101 | #cProfile.run('explore.brute_force(p, cpu, 0xe000, 0x10000)') 102 | #explore.brute_force(p, cpu, 0x0000, 0x0800) 103 | 104 | while p.run(): 105 | pass 106 | 107 | cpu.to_tree() 108 | 109 | ####################################################################### 110 | 111 | p.setlabel(0x0df, "rr(adr=@r1,wid=r4)") 112 | p.setlabel(0x16f, "r2:r3=sum(0x48:0x49,0x2f:0x30)") 113 | p.setlabel(0x1dd, "inc(adr=@R0,wid=R1)") 114 | p.setlabel(0x2f0, "toggle_P1.7()") 115 | p.setlabel(0x6a5, "delay(someN)") 116 | p.setlabel(0x6b2, "memcpy(0x1d,0x35,3)") 117 | p.setlabel(0x6b8, "memcpy(r0,r1,r6)") 118 | 119 | ####################################################################### 120 | # Build code graph 121 | 122 | if True: 123 | p.g = topology.topology(p) 124 | p.g.build_bb() 125 | p.g.segment() 126 | p.g.setlabels(p) 127 | p.g.dump_dot() 128 | p.g.xxx(p) 129 | 130 | ####################################################################### 131 | # Render output 132 | 133 | print("Render") 134 | r = render.render(p) 135 | r.add_flows() 136 | r.render("/tmp/_.cbm900_wdcd.txt") 137 | -------------------------------------------------------------------------------- /tasks/cdp1802_test/cdp1802.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/cdp1802_test/cdp1802.bin -------------------------------------------------------------------------------- /tasks/cdp1802_test/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a demo-task which disassembles a cdp1802 ROM image. 4 | # 5 | # I have no idea what this ROM image does. It is from a PCB I found in a 6 | # scrap-heap many years ago. 7 | # 8 | # The CDP1802 is a very challenging CPU to disassemble, because of the 9 | # indirect register PC. We are not doing a very good job of it yet. 10 | 11 | ####################################################################### 12 | # Check the python version 13 | 14 | import sys 15 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 16 | 17 | ####################################################################### 18 | # Set up a search path to two levels below 19 | 20 | import os 21 | sys.path.insert(0, os.path.abspath(os.path.join(".", "..", ".."))) 22 | 23 | ####################################################################### 24 | # Stuff we need... 25 | 26 | import mem 27 | import pyreveng 28 | import topology 29 | import render 30 | import cpus.cdp1802 31 | 32 | ####################################################################### 33 | # Set up the memory image 34 | m = mem.byte_mem(0,0x800, 0, True, "big-endian") 35 | m.fromfile("cdp1802.bin", 0x0000, 1) 36 | m.bcols = 3 37 | 38 | ####################################################################### 39 | # Instantiate pyreveng instance 40 | p = pyreveng.pyreveng(m) 41 | 42 | ####################################################################### 43 | # Instantiate a disassembler 44 | cpu = cpus.cdp1802.cdp1802(p) 45 | 46 | ####################################################################### 47 | # Provide hints for disassembly 48 | cpu.vectors(p) 49 | 50 | # Subr R(4) 51 | cpu.disass(0x644) 52 | x = p.t.add(0x0644,0x0654, "subr") 53 | p.setlabel(0x0644, "SUBR R(4)") 54 | 55 | # Subr R(5) 56 | cpu.disass(0x654) 57 | x = p.t.add(0x0654,0x0661, "subr") 58 | p.setlabel(0x0654, "SUBR R(5)") 59 | 60 | p.setlabel(0x06b9, "R15 = (R13++)") 61 | p.setlabel(0x06be, "(R13++) = R15") 62 | p.setlabel(0x06c5, "R15 = -R15") 63 | 64 | ####################################################################### 65 | # Chew through what we got 66 | 67 | while p.run(): 68 | pass 69 | 70 | ####################################################################### 71 | # 72 | 73 | import explore 74 | 75 | explore.brute_force(p, cpu, 0x000, 0x800) 76 | 77 | ####################################################################### 78 | # 79 | 80 | cpu.to_tree() 81 | 82 | ####################################################################### 83 | # Build code graph 84 | if True: 85 | p.g = topology.topology(p.t) 86 | p.g.segment() 87 | p.g.setlabels(p) 88 | p.g.dump_dot() 89 | p.g.xxx(p) 90 | 91 | ####################################################################### 92 | # Render output 93 | 94 | r = render.render(p) 95 | r.add_flows() 96 | r.render("/tmp/_.cdp1802.txt") 97 | -------------------------------------------------------------------------------- /tasks/domus/__.CATLI: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/domus/__.CATLI -------------------------------------------------------------------------------- /tasks/domus/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a "real" task which disassembles DOMUS relocatable binaries 4 | # from RC3600 or RC7000 DOMUS systems. 5 | # 6 | # If you have never heard of either, you're not alone. 7 | # 8 | # RegneCentralen was a Danish computer manufacturer. 9 | # The RC7000 computer were a rebadged Data General Nova. 10 | # The RC3600 was a re-engineered version built in Denmark. 11 | # More info: http://www.datamuseum.dk 12 | # 13 | # The reason this is a good test-case for PyRevEng is that it typically 14 | # are pretty small programs, the OS is well documented and, most importantly, 15 | # may of the programs contain interpreted code, for the "MUSIL" language. 16 | # 17 | # I have included the "CATLI" program here, it produces a "CATalog LIst", 18 | # of the filesystem. 19 | # 20 | # Yell at me if you want docs for this platforms, we have tons of pdfs. 21 | 22 | #---------------------------------------------------------------------- 23 | # Check the python version 24 | 25 | import sys 26 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 27 | 28 | #---------------------------------------------------------------------- 29 | # Set up a search path to two levels below 30 | 31 | import os 32 | sys.path.insert(0, os.path.abspath(os.path.join(".", "..", ".."))) 33 | 34 | #---------------------------------------------------------------------- 35 | # Stuff we need... 36 | 37 | import domus.do_file 38 | import domus.inter.inter as inter 39 | 40 | print(sys.argv) 41 | 42 | targets = ("__.CATLI",) 43 | 44 | if len(sys.argv) > 1: 45 | targets = sys.argv[1:] 46 | 47 | for tf in targets: 48 | print("Target: ", tf) 49 | load_file = domus.do_file.find_file(tf) 50 | 51 | oi = load_file.build_index() 52 | 53 | for obj in oi: 54 | p = domus.do_file.load_obj(load_file, obj, True) 55 | i = inter.inter(p) 56 | 57 | p.c["domus"].pz_entries() 58 | 59 | domus.do_file.auto_magic(p) 60 | domus.do_file.auto_hints(p) 61 | 62 | domus.do_file.finish(p) 63 | -------------------------------------------------------------------------------- /tasks/mc6800_hp53xx/HP5359A.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/mc6800_hp53xx/HP5359A.ROM -------------------------------------------------------------------------------- /tasks/mc6800_hp53xx/HP5370A.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/mc6800_hp53xx/HP5370A.ROM -------------------------------------------------------------------------------- /tasks/mc6800_hp53xx/HP5370B.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/mc6800_hp53xx/HP5370B.ROM -------------------------------------------------------------------------------- /tasks/mc6800_hp53xx/hp5370.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Functions common to: 4 | # HP 5370A 5 | # HP 5370B 6 | 7 | # PyRevEng classes 8 | import tree 9 | import math 10 | import const 11 | 12 | def chargen(p, adr): 13 | for a in range(adr, adr + 16): 14 | const.seven_segment(p, a) 15 | p.setlabel(adr, "CHARGEN") 16 | 17 | ####################################################################### 18 | # 19 | 20 | def keyboard_dispatch(p, cpu, adr = 0x7962): 21 | assert p.m.rd(adr) == 0xce 22 | assert p.m.rd(adr + 3) == 0x7e 23 | ptr = p.m.b16(adr + 1) 24 | 25 | ii = cpu.disass(adr + 3, "ins") 26 | 27 | const.ptr(p, ptr, 2) 28 | tbl = p.m.b16(ptr) 29 | 30 | aa = tbl 31 | xx = dict() 32 | for col in range(8,0,-1): 33 | p.setlabel(aa, "Keyboard_Column_%d" % col) 34 | for row in range(1,5): 35 | x = const.ptr(p, aa, 2) 36 | dd = p.m.b16(aa) 37 | cpu.disass(dd) 38 | if dd not in xx: 39 | ii.flow("call", "XFUNC", dd) 40 | xx[dd] = True 41 | aa += 2 42 | x = p.t.add(tbl, aa, "tbl") 43 | x.blockcmt += "-\nDispatch table for Keyboard commands\n" 44 | 45 | p.setlabel(p.m.b16(tbl + 4), "KEY_Ext_Arm") 46 | p.setlabel(p.m.b16(tbl + 6), "KEY_UNDEF") 47 | p.setlabel(p.m.b16(tbl + 10), "KEY_Ext_Hold_Off") 48 | p.setlabel(p.m.b16(tbl + 14), "KEY_Reset") 49 | 50 | ####################################################################### 51 | # List of two-letter HPIB commands 52 | # 53 | 54 | def hpib_cmd_table(p, adr, len = 26): 55 | p.hpib_cmd = list() 56 | x = p.t.add(adr, adr + 2 * len, "cmd-table") 57 | x.blockcmt += "-\nTable of two-letter HPIB commands\n" 58 | for i in range(adr, adr + 2 * len, 2): 59 | const.txtlen(p,i,2) 60 | p.hpib_cmd.append([p.m.ascii(i, 2),]) 61 | 62 | def hpib_arg_range(p, adr, len = 14): 63 | x = p.t.add(adr, adr + len * 2, "arg-range") 64 | x.blockcmt += "-\nTable of legal range of numeric argument for HPIB cmd" 65 | for i in range(0, len): 66 | aa = adr + i * 2 67 | x = const.byte(p, aa, 2) 68 | l = p.m.rd(aa) 69 | h = p.m.rd(aa + 1) 70 | x.lcmt(p.hpib_cmd[i][0] + "[%d-%d]" % (l,h)) 71 | p.hpib_cmd[i].append(l) 72 | p.hpib_cmd[i].append(h) 73 | 74 | def hpib_tbl_idx(p, adr): 75 | aa = adr 76 | for i in p.hpib_cmd: 77 | if len(i) == 1: 78 | break 79 | x = const.byte(p, aa) 80 | i.append(p.m.rd(aa)) 81 | x.lcmt(i[0]) 82 | aa += 1 83 | x = p.t.add(adr, aa, "idx-table") 84 | x.blockcmt += "-\nIndex into cmd table, add numeric arg" 85 | 86 | def dispatch_table_arg(p, adr, cpu): 87 | assert p.m.rd(adr) == 0xce 88 | assert p.m.rd(adr + 3) == 0x7e 89 | ptr = p.m.b16(adr + 1) 90 | ii = cpu.disass(adr + 3, "ins") 91 | 92 | const.ptr(p, ptr, 2) 93 | tbl = p.m.b16(ptr) 94 | 95 | aa = tbl 96 | xx = dict() 97 | for i in p.hpib_cmd: 98 | if len(i) == 1: 99 | break 100 | for j in range(i[1], i[2] + 1): 101 | x = const.ptr(p, aa, 2) 102 | y = i[0] + "%d" % j 103 | dd = p.m.b16(aa) 104 | cpu.disass(dd) 105 | if dd not in xx: 106 | ii.flow("call", "XFUNC", dd) 107 | xx[dd] = True 108 | p.setlabel(dd, "CMD_" + y + "_" + gpib_expl[y]) 109 | aa += 2 110 | x = p.t.add(tbl, aa, "idx-table") 111 | x.blockcmt += "-\nDispatch table for HPIB cmds with arg" 112 | 113 | def dispatch_table_noarg(p, adr, cpu): 114 | assert p.m.rd(adr) == 0xce 115 | assert p.m.rd(adr + 3) == 0x7e 116 | ptr = p.m.b16(adr + 1) 117 | ii = cpu.disass(adr + 3, "ins") 118 | 119 | const.ptr(p, ptr, 2) 120 | tbl = p.m.b16(ptr) 121 | 122 | aa = tbl 123 | xx = dict() 124 | for i in p.hpib_cmd: 125 | if len(i) > 1: 126 | continue 127 | x = const.ptr(p, aa, 2) 128 | y = i[0] 129 | dd = p.m.b16(aa) 130 | cpu.disass(dd) 131 | if dd not in xx: 132 | ii.flow("call", "XFUNC", dd) 133 | xx[dd] = True 134 | p.setlabel(dd, "CMD_" + y + "_" + gpib_expl[y]) 135 | aa += 2 136 | x = p.t.add(tbl, aa, "idx-table") 137 | x.blockcmt += "-\nDispatch table for HPIB cmds without arg\n" 138 | 139 | 140 | # Explanation of the HP5370[AB] HPIB Commands 141 | gpib_expl = { 142 | "FN1": "Time Interval", 143 | "FN2": "Trigger Levels", 144 | "FN3": "Frequency", 145 | "FN4": "Period", 146 | "FN5": "???", 147 | "GT1": "Single Period", 148 | "GT2": "0.01s", 149 | "GT3": "0.1s", 150 | "GT4": "1s", 151 | "ST1": "Mean", 152 | "ST2": "StdDev", 153 | "ST3": "Min", 154 | "ST4": "Max", 155 | "ST5": "Disp Ref", 156 | "ST6": "Clr Ref", 157 | "ST7": "Disp Evts", 158 | "ST8": "Set Ref", 159 | "ST9": "Disp All", 160 | "SS1": "Sample Size = 1", 161 | "SS2": "Sample Size = 100", 162 | "SS3": "Sample Size = 1k", 163 | "SS4": "Sample Size = 10k", 164 | "SS5": "Sample Size = 100k", 165 | "MD1": "FP Rate", 166 | "MD2": "Hold until MR", 167 | "MD3": "Fast", 168 | "MD4": "Fast + SRQ", 169 | "IN1": "Input: Start+Stop", 170 | "IN2": "Input: Stop+Stop", 171 | "IN3": "Input: Start+Start", 172 | "IN4": "Input: Stop+Start", 173 | "SA1": "Start Pos", 174 | "SA2": "Start Neg", 175 | "SO1": "Stop Pos", 176 | "SO2": "Stop Neg", 177 | "SE1": "Arm Pos", 178 | "SE2": "Arm Neg", 179 | "AR1": "+T.I. Arming Only", 180 | "AR2": "+T.I. Arming", 181 | "EH0": "Ext Holdoff dis", 182 | "EH1": "Ext Holdoff ena", 183 | "EA0": "Ext Arm dis", 184 | "EA1": "Ext Arm ena", 185 | "IA1": "Internal Arm Auto", 186 | "IA2": "Start Chan Arm", 187 | "IA3": "Stop Chan Arm", 188 | "MR": "Manual Rate", 189 | "MI": "Manual Input", 190 | "SL": "Slope Local", 191 | "SR": "Slope Remote", 192 | "TL": "Trigger Local", 193 | "TR": "Trigger Remote", 194 | "TE": "Teach", 195 | "PC": "Period Complement", 196 | "TB0": "Ascii", 197 | "TB1": "Binary", 198 | "SB": "Sample Size Binary", 199 | "LN": "Learn", 200 | "TA": "Trigger Start", 201 | "TO": "Trigger Stop", 202 | } 203 | 204 | ####################################################################### 205 | # HP5370B uses its own (weird|smart) floating point format. 206 | # 207 | # As far as I can tell, it looks like this: S{1}M{47}E{8} where the 208 | # exponent is 2's complement. But there are two scaling factors 209 | # involved, so the value is: (S * M{31.16} * 2^e * 5e-9) 210 | # 211 | # XXX: Hmm, the mantissa may be a 32.16 2' complement number... 212 | # 213 | 214 | def float_render(p, a): 215 | x = p.m.rd(a + 0) 216 | if x & 0x80: 217 | s = -1 218 | x ^= 0x80 219 | else: 220 | s = 1 221 | m = math.ldexp(x, 24) 222 | m += math.ldexp(p.m.rd(a + 1), 16) 223 | m += math.ldexp(p.m.rd(a + 2), 8) 224 | m += math.ldexp(p.m.rd(a + 3), 0) 225 | m += math.ldexp(p.m.rd(a + 4), -8) 226 | m += math.ldexp(p.m.rd(a + 5), -16) 227 | e = p.m.s8(a + 6) 228 | v = math.ldexp(m * 5e-9, e) 229 | x = "%.9e" % v 230 | if x.find(".") == -1 and x.find("e") == -1: 231 | x = x + "." 232 | print("FLOAT", "%x" % a, x) 233 | return x 234 | 235 | class float(tree.tree): 236 | def __init__(self, p, adr): 237 | tree.tree.__init__(self, adr, adr + 7, "dot_float") 238 | p.t.add(adr, adr + 7, "dot-float", True, self) 239 | self.render = self.rfunc 240 | self.nbr = float_render(p, adr) 241 | self.a['const'] = "FP=" + self.nbr 242 | 243 | def rfunc(self, p, t): 244 | s = ".FLOAT\t%s" % self.nbr 245 | return (s,) 246 | 247 | 248 | ########################################################### 249 | 250 | def dsp_dispatch(p, cpu, adr = 0x683b): 251 | assert p.m.rd(adr) == 0xce 252 | assert p.m.rd(adr + 3) == 0xbd 253 | tbl = p.m.b16(adr + 1) 254 | ii = cpu.disass(adr + 3) 255 | 256 | p.setlabel(tbl, "DSP_FUNC_TABLE") 257 | x=p.t.add(tbl, tbl + 8 * 2, "tbl") 258 | x.blockcmt += "-\nTable of display functions\n" 259 | dspf= ("AVG", "STD", "MIN", "MAX", "REF", "EVT", "DS6", "ALL") 260 | j=0 261 | for i in range(tbl, tbl + 8 * 2, 2): 262 | x = const.ptr(p, i, 2) 263 | w = p.m.b16(i) 264 | p.setlabel(w, "DSP_" + dspf[j]) 265 | ii.flow("call", "DSPFUNC", w) 266 | cpu.disass(w) 267 | j += 1 268 | 269 | ########################################################### 270 | #x = p.t.add(0x6f00,0x7000, "tbl") 271 | #x.blockcmt += "Table of I^2>>8\n" 272 | 273 | def sqare_table_render(p, t): 274 | return ( 275 | "FOR I (0..255):", 276 | " .BYTE ((I * I) >> 8)", 277 | "" 278 | ) 279 | 280 | def square_table(p, adr = 0x6f00): 281 | x = p.t.add(0x6f00,0x7000, "tbl") 282 | x.blockcmt += "-\nTable of I^2>>8\n" 283 | x.render = sqare_table_render 284 | x.fold = True 285 | 286 | -------------------------------------------------------------------------------- /tasks/mc6800_hp53xx/hp53xx.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # Functions common to: 4 | # HP 5370B 5 | # HP 5359A 6 | # May also be relevant to: 7 | # HP 5342A 8 | 9 | # PyRevEng classes 10 | import const 11 | 12 | #---------------------------------------------------------------------- 13 | # Structure of (virtual) EPROMS 14 | # 15 | def one_eprom(p, disass, start, eprom_size): 16 | 17 | if False: 18 | x = p.t.add(start, start + eprom_size, "eprom") 19 | x.blockcmt += "\n-\nEPROM at 0x%x-0x%x\n\n" % \ 20 | (start, start + eprom_size - 1) 21 | 22 | # Calculate checksum 23 | j = 0^p.m.w16(start) 24 | for jj in range(2, eprom_size): 25 | j += p.m.rd(start + jj) 26 | j &= 0xffff 27 | if j == 0xffff: 28 | j = "OK" 29 | else: 30 | print("NB: Bad Eprom checksum @%x" % start) 31 | j = "BAD" 32 | 33 | x = const.w16(p, start) 34 | x.cmt.append("EPROM checksum (%s)" % j) 35 | x.blockcmt += "-\nEPROM %04x\n" % start 36 | 37 | x = const.byte(p, start + 2) 38 | x.cmt.append("EPROM identifier") 39 | 40 | # Jump table at front of EPROM 41 | for ax in range(start + 3, start + eprom_size, 3): 42 | if p.m.rd(ax) != 0x7e: 43 | break 44 | disass(ax) 45 | 46 | def eprom(p, disass, start, end, sz): 47 | lx = list() 48 | for ax in range(start, end, sz): 49 | lx.append(ax >> 8) 50 | lx.append(ax & 0xff) 51 | one_eprom(p, disass, ax, sz) 52 | lx.append(end >> 8) 53 | lx.append(end & 0xff) 54 | 55 | # Find the table of eprom locations 56 | l = p.m.find(start, end, lx) 57 | print("EPROM", l) 58 | assert len(l) == 1 59 | x = p.t.add(l[0], l[0] + len(lx), "tbl") 60 | x.blockcmt += "-\nTable of EPROM locations" 61 | for ax in range(x.start, x.end, 2): 62 | const.w16(p, ax) 63 | p.setlabel(l[0], "EPROM_TBL") 64 | 65 | #---------------------------------------------------------------------- 66 | # Write test values 67 | # 68 | 69 | def wr_test_val(p, start = 0x6000, end = 0x8000): 70 | px = ( 0x00, 0xff, 0xaa, 0x55, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01) 71 | l = p.m.find(start, end, px) 72 | assert len(l) == 1 73 | ax = l[0] 74 | x = p.t.add(ax, ax + len(px), "tbl") 75 | print("WR_TEST_VAL", x) 76 | x.blockcmt += "-\nWrite Test Values" 77 | p.setlabel(ax, "WR_TEST_VAL") 78 | for i in range(x.start, x.end): 79 | const.byte(p, i) 80 | 81 | def nmi_debugger(p, cpu): 82 | ####################################################################### 83 | # NMI/GPIB debugger 84 | nmi = p.m.w16(0x7ffc) 85 | 86 | xnmi = p.t.add(nmi, 0x7ff8, "src") 87 | xnmi.blockcmt += """- 88 | NMI based GPIB debugger interface. 89 | See HPJ 1978-08 p23 90 | """ 91 | 92 | i = nmi 93 | l = list() 94 | while True: 95 | j = cpu.disass(i) 96 | if j.status == "prospective": 97 | print("Error: nmi_debugger called too early") 98 | return 99 | i = j.hi 100 | l.append(j) 101 | if j.mne == "BRA": 102 | break 103 | 104 | ll = None 105 | for i in l: 106 | if i.mne == "BSR": 107 | p.setlabel(i.lo, "NMI_LOOP()") 108 | x = i.flow_out[0][2] 109 | p.setlabel(x, "NMI_RX_A()") 110 | if i.mne == "CMPA": 111 | ll = i.oper[0] 112 | if i.mne == "BEQ": 113 | x = i.flow_out[1][2] 114 | if ll == "#0x01": 115 | p.setlabel(x, "NMI_CMD_01_WRITE() [X,L,D...]") 116 | elif ll == "#0x02": 117 | p.setlabel(x, "NMI_CMD_02_READ() [X,L]") 118 | kk = cpu.disass(x) 119 | p.setlabel(kk.flow_out[0][2], 120 | "NMI_RX_X()") 121 | elif ll == "#0x03": 122 | p.setlabel(x, "NMI_CMD_03()") 123 | elif ll == "#0x04": 124 | p.setlabel(x, "NMI_CMD_04_TX_X()") 125 | kk = cpu.disass(x) 126 | while kk.mne != "BSR": 127 | kk = cpu.disass(kk.hi) 128 | p.setlabel(kk.flow_out[0][2], 129 | "NMI_TX_A()") 130 | else: 131 | print(i, ll) 132 | if i.mne == "BRA": 133 | x = i.flow_out[0][2] 134 | p.setlabel(x, "NMI_CMD_05_END()") 135 | 136 | #---------------------------------------------------------------------- 137 | # 138 | 139 | def gpib_board(p): 140 | 141 | p.t.blockcmt += """- 142 | 0x0000-0x0003 GPIB BOARD (A15) {See HP5370B manual P8-30} 143 | 144 | 0x0000:R Data In 145 | 0x0000:W Data Out 146 | 0x0001:R Inq In 147 | 0x0001:W Status Out (P3-18) 148 | 0x80 = Running NMI Debug monitor 149 | 0x40 = Service Requested 150 | 0x20 = Oven heater on 151 | 0x10 = External Timebase 152 | 0x0f = Error message if bit 7 "is used" 153 | 0x0002:R Cmd In 154 | 0x0002:W Control Out 155 | 0x02 = NMI gate 156 | 0x10 = EOI out {0x61e9} 157 | 0x0003:R State In 158 | 159 | """ 160 | 161 | p.setlabel(0x0000, "HPIB__DATA_IN__DATA_OUT") 162 | p.setlabel(0x0001, "HPIB__INQ_IN__STATUS_OUT") 163 | p.setlabel(0x0002, "HPIB__CMD_IN__CTRL_OUT") 164 | p.setlabel(0x0003, "HPIB__STATE_IN") 165 | 166 | #---------------------------------------------------------------------- 167 | # 168 | 169 | def display_board(p): 170 | 171 | p.t.blockcmt += """- 172 | 0x0060-0x007f DISPLAY BOARD (A11) 173 | 174 | 0x0060:R Buttons 175 | 0xf0: scan lines 176 | 0x07: sense lines 177 | 0x0060-0x006f:W LEDS 178 | 0x0070-0x007f:W 7segs 179 | 180 | """ 181 | 182 | p.setlabel(0x0060, "DISPLAY__KBD_IN__LED#0_OUT") 183 | p.setlabel(0x0070, "DISPLAY__7SEG#0_OUT") 184 | for i in range (1,16): 185 | p.setlabel(0x0070 + i, "DISPLAY__7SEG#%d_OUT" % i) 186 | p.setlabel(0x0060 + i, "DISPLAY__LED#%d_OUT" % i) 187 | 188 | -------------------------------------------------------------------------------- /tasks/mcs4_micrologic_ml200/P1702.hex: -------------------------------------------------------------------------------- 1 | # This is the contents of the 1702 EPROM in my MicroLogic ML-200 2 | # Loran-C receiver 3 | 00 26 4 | 01 e8 5 | 02 23 6 | 03 d3 7 | 04 e1 8 | 05 d1 9 | 06 e1 10 | 07 77 11 | 08 03 12 | 09 76 13 | 0a 03 14 | 0b 45 15 | 0c fe 16 | 0d f0 17 | 0e f0 18 | 0f f0 19 | 10 f0 20 | 11 f0 21 | 12 f0 22 | 13 20 23 | 14 02 24 | 15 22 25 | 16 f0 26 | 17 24 27 | 18 d0 28 | 19 21 29 | 1a e9 30 | 1b 23 31 | 1c e0 32 | 1d 61 33 | 1e 63 34 | 1f 74 35 | 20 19 36 | 21 23 37 | 22 ec 38 | 23 e0 39 | 24 28 40 | 25 f0 41 | 26 56 42 | 27 ec 43 | 28 28 44 | 29 f4 45 | 2a 58 46 | 2b a4 47 | 2c 26 48 | 2d 30 49 | 2e 57 50 | 2f 9c 51 | 30 28 52 | 31 c0 53 | 32 56 54 | 33 ec 55 | 34 28 56 | 35 fa 57 | 36 58 58 | 37 a4 59 | 38 26 60 | 39 32 61 | 3a 57 62 | 3b 9c 63 | 3c 26 64 | 3d 30 65 | 3e 27 66 | 3f f0 67 | 40 28 68 | 41 40 69 | 42 ed 70 | 43 88 71 | 44 e5 72 | 45 ee 73 | 46 89 74 | 47 e6 75 | 48 22 76 | 49 b3 77 | 4a 24 78 | 4b 60 79 | 4c 23 80 | 4d a3 81 | 4e e1 82 | 4f d1 83 | 50 e1 84 | 51 20 85 | 52 80 86 | 53 21 87 | 54 d5 88 | 55 e1 89 | 56 2c 90 | 57 70 91 | 58 2e 92 | 59 f0 93 | 5a d1 94 | 5b e1 95 | 5c f0 96 | 5d 2f 97 | 5e e9 98 | 5f 2d 99 | 60 e2 100 | 61 20 101 | 62 00 102 | 63 20 103 | 64 00 104 | 65 26 105 | 66 e0 106 | 67 25 107 | 68 f0 108 | 69 ea 109 | 6a 7f 110 | 6b 5d 111 | 6c 48 112 | 6d 79 113 | 6e 2a 114 | 6f 00 115 | 70 2e 116 | 71 0c 117 | 72 23 118 | 73 a3 119 | 74 e1 120 | 75 d1 121 | 76 e1 122 | 77 25 123 | 78 ea 124 | 79 2d 125 | 7a e2 126 | 7b 77 127 | 7c 6e 128 | 7d dd 129 | 7e b7 130 | 7f 76 131 | 80 72 132 | 81 2a 133 | 82 30 134 | 83 f0 135 | 84 20 136 | 85 00 137 | 86 2b 138 | 87 e9 139 | 88 2d 140 | 89 e2 141 | 8a 20 142 | 8b 00 143 | 8c 20 144 | 8d 00 145 | 8e f0 146 | 8f 6b 147 | 90 7f 148 | 91 83 149 | 92 20 150 | 93 00 151 | 94 f0 152 | 95 2b 153 | 96 ed 154 | 97 2d 155 | 98 e2 156 | 99 20 157 | 9a 0d 158 | 9b f0 159 | 9c 71 160 | 9d 9b 161 | 9e 2b 162 | 9f ee 163 | a0 2d 164 | a1 e2 165 | a2 42 166 | a3 b5 167 | a4 da 168 | a5 bf 169 | a6 a9 170 | a7 be 171 | a8 f0 172 | a9 29 173 | aa e0 174 | ab 69 175 | ac 7f 176 | ad a9 177 | ae ae 178 | af b9 179 | b0 aa 180 | b1 f5 181 | b2 f1 182 | b3 f5 183 | b4 ba 184 | b5 22 185 | b6 cb 186 | b7 23 187 | b8 e9 188 | b9 f6 189 | ba aa 190 | bb f6 191 | bc f6 192 | bd ba 193 | be 22 194 | bf fa 195 | c0 d6 196 | c1 89 197 | c2 1a 198 | c3 c6 199 | c4 22 200 | c5 ca 201 | c6 23 202 | c7 ef 203 | c8 1c 204 | c9 d2 205 | ca f0 206 | cb ed 207 | cc 14 208 | cd d2 209 | ce 83 210 | cf 12 211 | d0 d2 212 | d1 c0 213 | d2 f0 214 | d3 de 215 | d4 81 216 | d5 1c 217 | d6 dd 218 | d7 a7 219 | d8 f8 220 | d9 b7 221 | da ac 222 | db f8 223 | dc bc 224 | dd 27 225 | de e9 226 | df 29 227 | e0 e0 228 | e1 67 229 | e2 69 230 | e3 7c 231 | e4 dd 232 | e5 c0 233 | e6 00 234 | e7 00 235 | e8 00 236 | e9 00 237 | ea 00 238 | eb 00 239 | ec 00 240 | ed 00 241 | ee 00 242 | ef 00 243 | f0 00 244 | f1 00 245 | f2 00 246 | f3 00 247 | f4 00 248 | f5 00 249 | f6 00 250 | f7 00 251 | f8 00 252 | f9 00 253 | fa 00 254 | fb 00 255 | fc 00 256 | fd 00 257 | fe 00 258 | ff 00 259 | -------------------------------------------------------------------------------- /tasks/mcs4_micrologic_ml200/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a demo-task which disassembles the MicroLogic ML200 Loran-C 4 | # Receiver 5 | # 6 | 7 | ####################################################################### 8 | # Check the python version 9 | 10 | import sys 11 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 12 | 13 | ####################################################################### 14 | # Set up a search path to two levels below 15 | 16 | import os 17 | sys.path.insert(0, os.path.abspath(os.path.join(".", "..", ".."))) 18 | 19 | ####################################################################### 20 | # Stuff we need... 21 | import mem 22 | import const 23 | import pyreveng 24 | import render 25 | import topology 26 | import cpus.mcs4 27 | 28 | 29 | ####################################################################### 30 | # Set up the memory image 31 | m0 = mem.byte_mem(0, 0x001000, 0, True, "little-endian") 32 | 33 | m0.fromhexfile("P8316.hex", 0x0000, 1) 34 | for i in range(0x800, 0x0900, 0x100): 35 | m0.fromhexfile("P1702.hex", i, 1) 36 | m0.bcols=2 37 | 38 | ####################################################################### 39 | # Create a pyreveng instance 40 | p = pyreveng.pyreveng(m0) 41 | 42 | ####################################################################### 43 | 44 | p.t.blockcmt += """- 45 | - 46 | """ 47 | 48 | 49 | const.fill(p, mid=0x198) 50 | const.fill(p, mid=0x6e7) 51 | const.fill(p, mid=0x7ff) 52 | const.fill(p, mid=0x80f) 53 | const.fill(p, mid=0x8f5) 54 | 55 | ####################################################################### 56 | cpu = cpus.mcs4.mcs4(p) 57 | 58 | ####################################################################### 59 | 60 | cpu.disass(0) 61 | 62 | ####################################################################### 63 | 64 | while p.run(): 65 | pass 66 | 67 | ####################################################################### 68 | 69 | cpu.to_tree() 70 | 71 | ####################################################################### 72 | 73 | for a in range(0x66a, 0x676, 3): 74 | w = p.m.l16(a) 75 | x = const.byte(p, a, len=3, fmt="%d") 76 | p.setlabel(a, "CONST_%d" % w) 77 | 78 | p.setlabel(0x6e8, "rr0++") 79 | 80 | ####################################################################### 81 | p.setlabel(0x6bc, "Count_Down()") 82 | x = p.t.find(0x6bc, "ins") 83 | x.blockcmt += """- 84 | This is the RESET "countdown" routine 85 | 86 | Displays: 87 | .9.9.9.9 9.9 88 | .8.8.8.8 8.8 89 | ... 90 | .0.0.0.0 0.0 91 | 92 | It calls 0x5ca a lot, presumably to let the analog stuff settle ? 93 | 94 | """ 95 | ####################################################################### 96 | p.setlabel(0x7df, "Update_Display()") 97 | x = p.t.find(0x7df, "ins") 98 | x.blockcmt += """- 99 | The display is driven by two chains of 3 three P4003 10-bit shift 100 | registers, which again drives 7447 7-segment drivers. 101 | 102 | On entry r2 contains 0x20 or 0x40, depending on which clock-pulse 103 | line should be driven. 104 | 105 | A total of 30 pulses are sent: 106 | 107 | 6 x 1 Decimal points, left to right 108 | 6 x 4 BCD to 7447, LSD to MSD order. 109 | 110 | """ 111 | ####################################################################### 112 | # Build code graph 113 | 114 | if True: 115 | p.g = topology.topology(p) 116 | p.g.build_bb() 117 | p.g.segment() 118 | p.g.setlabels(p) 119 | p.g.dump_dot() 120 | p.g.xxx(p) 121 | 122 | ####################################################################### 123 | 124 | import pseudo 125 | 126 | regs = dict() 127 | regs["rc"] = 1 128 | regs["ra"] = 4 129 | for i in range(0,16): 130 | regs["r%d" %i] = 4 131 | regs["rsrc"] = 8 132 | regs["rdcl"] = 11 133 | 134 | def fbb(tree, priv, lvl): 135 | if tree.tag == "bb": 136 | pseudo.pseudo_test(tree, regs) 137 | 138 | p.t.recurse(fbb) 139 | 140 | ####################################################################### 141 | # Render output 142 | 143 | print("Render") 144 | r = render.render(p) 145 | r.add_flows() 146 | r.render("/tmp/_.mcs4.txt") 147 | -------------------------------------------------------------------------------- /tasks/z8000_test/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a demo-task which disassembles a Z8000 ROM image. 4 | # 5 | # I belive the roms in question are the boot-roms from a 6 | # Zilog S8000/21 UNIX computer. 7 | # 8 | # NB: the Z8000 disassembler is not very good yet 9 | # 10 | 11 | ####################################################################### 12 | # Check the python version 13 | 14 | import sys 15 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 16 | 17 | ####################################################################### 18 | # Set up a search path to two levels below 19 | 20 | import os 21 | sys.path.insert(0, os.path.abspath(os.path.join(".", "..", ".."))) 22 | 23 | ####################################################################### 24 | # Stuff we need... 25 | import mem 26 | import const 27 | import pyreveng 28 | import render 29 | import topology 30 | import cpus.z8000 31 | 32 | 33 | ####################################################################### 34 | # Set up the memory image 35 | m = mem.byte_mem(0, 0x4000, 0, True, "big-endian") 36 | m.fromfile("u93.bin", 0, 2) 37 | m.fromfile("u91.bin", 1, 2) 38 | m.fromfile("u94.bin", 0x2000, 2) 39 | m.fromfile("u92.bin", 0x2001, 2) 40 | m.bcols=8 41 | 42 | ####################################################################### 43 | # Create a pyreveng instance 44 | p = pyreveng.pyreveng(m) 45 | 46 | ####################################################################### 47 | # Instantiate a disassembler 48 | cpu = cpus.z8000.z8000(p) 49 | 50 | ####################################################################### 51 | # Provide hints for disassembly 52 | const.w16(p, 0) 53 | const.w16(p, 2) 54 | const.w16(p, 4) 55 | const.w16(p, 6) 56 | 57 | cpu.disass(p.m.b16(6)) 58 | 59 | ####################################################################### 60 | # More hints... 61 | 62 | if False: 63 | # Args to 0x050c and 0x12f0 64 | def lstr(p, a): 65 | const.w16(p, a) 66 | const.txtlen(p, a + 2, p.m.b16(a)) 67 | 68 | lstr(p, 0x0024) 69 | lstr(p, 0x0d42) 70 | lstr(p, 0x0d98) 71 | lstr(p, 0x1214) 72 | lstr(p, 0x1228) 73 | lstr(p, 0x123c) 74 | lstr(p, 0x1250) 75 | lstr(p, 0x126a) 76 | 77 | # Args to SC(0x0c) 78 | lstr(p, 0x13a0) 79 | lstr(p, 0x13ae) 80 | 81 | 82 | if False: 83 | # Moved to 0xf800 for exec 84 | x = p.t.add(0x2c68, 0x2c68 + 0xc6, "blk") 85 | cpu.disass(0x2c68) 86 | x = p.t.add(0x2d48, 0x2d48 + 0xc6, "blk") 87 | cpu.disass(0x2d48) 88 | 89 | if False: 90 | # From 0x1544 ? 91 | # Looks like it's called from segmented mode ?? 92 | cpu.disass(0x1ab8) 93 | 94 | if False: 95 | for i in range(0, 16): 96 | t1 = p.m.rd(0x1b2 + i) 97 | t2 = p.m.b16(0x1c2 + 2 * i) 98 | const.w16(p, 0x1c2 + 2 * i) 99 | p.todo(t2, cpu.disass) 100 | p.setlabel(t2, "CMD_%c" % t1) 101 | 102 | if False: 103 | p.setlabel(0xa68, "OUTCHAR") 104 | p.setlabel(0xa80, "OUTNL") 105 | 106 | if False: 107 | # 0x43bc and 0x43ba pointers 108 | p.todo(0x0786, cpu.disass) 109 | p.todo(0x0766, cpu.disass) 110 | p.todo(0x0796, cpu.disass) 111 | p.todo(0x0776, cpu.disass) 112 | 113 | 114 | ####################################################################### 115 | # Chew through what we got 116 | 117 | while p.run(): 118 | pass 119 | 120 | cpu.to_tree() 121 | 122 | ####################################################################### 123 | # Build code graph 124 | 125 | if True: 126 | p.g = topology.topology(p) 127 | p.g.build_bb() 128 | p.g.segment() 129 | p.g.dump_dot() 130 | p.g.xxx(p) 131 | 132 | ####################################################################### 133 | # Render output 134 | 135 | r = render.render(p) 136 | r.add_flows() 137 | r.render("/tmp/_.z8000.txt") 138 | -------------------------------------------------------------------------------- /tasks/z8000_test/u91.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/z8000_test/u91.bin -------------------------------------------------------------------------------- /tasks/z8000_test/u92.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/z8000_test/u92.bin -------------------------------------------------------------------------------- /tasks/z8000_test/u93.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/z8000_test/u93.bin -------------------------------------------------------------------------------- /tasks/z8000_test/u94.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/z8000_test/u94.bin -------------------------------------------------------------------------------- /tasks/z80_rc702_bootrom/EPROM_ROA_375.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdphk/PyRevEng/08083744806258cfa31edd0132456d70377a9f71/tasks/z80_rc702_bootrom/EPROM_ROA_375.bin -------------------------------------------------------------------------------- /tasks/z80_rc702_bootrom/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | # 3 | # This is a demo-task which disassembles the "ROA375" bootrom from a 4 | # RC702 "Piccolo" CP/M computer 5 | # 6 | 7 | ####################################################################### 8 | # Check the python version 9 | 10 | import sys 11 | assert sys.version_info[0] >= 3 or "Need" == "Python v3" 12 | 13 | ####################################################################### 14 | # Set up a search path to two levels below 15 | 16 | import os 17 | sys.path.insert(0, os.path.abspath(os.path.join(".", "..", ".."))) 18 | 19 | ####################################################################### 20 | # Stuff we need... 21 | import mem 22 | import const 23 | import pyreveng 24 | import render 25 | import topology 26 | import cpus.z80 27 | 28 | ####################################################################### 29 | # Set up the memory image 30 | m0 = mem.byte_mem(0, 0x10000, 0, True, "little-endian") 31 | 32 | m0.fromfile("EPROM_ROA_375.bin", 0x0000, 1) 33 | m0.bcols=4 34 | 35 | 36 | ####################################################################### 37 | # Create a pyreveng instance 38 | p = pyreveng.pyreveng(m0) 39 | 40 | ####################################################################### 41 | # Copy to ram position 42 | 43 | for i in range(0x0069, 0x0800): 44 | y = m0.rd(i) 45 | d = 0x7000 + i - 0x0069 46 | m0.setflags(d, None, 47 | m0.can_read|m0.can_write, 48 | m0.invalid|m0.undef) 49 | m0.wr(d, y) 50 | 51 | t = p.t.add(0x0068,0x0800,"hide") 52 | t.render = "// Moved to 0x7000" 53 | t.fold = True 54 | 55 | ####################################################################### 56 | 57 | p.t.blockcmt += """- 58 | - 59 | """ 60 | 61 | #const.fill(p, mid=0x8f5) 62 | 63 | ####################################################################### 64 | cpu = cpus.z80.z80(p) 65 | 66 | cpu.io_port[0x00] = "DISP_PARAM" 67 | cpu.io_port[0x01] = "DISP_CMD" 68 | 69 | cpu.io_port[0x04] = "FLOP_STATUS" 70 | cpu.io_port[0x05] = "FLOP_DATA" 71 | 72 | cpu.io_port[0x08] = "SIO2_DATA_A" 73 | cpu.io_port[0x09] = "SIO2_DATA_B" 74 | cpu.io_port[0x0a] = "SIO2_CTRL_A" 75 | cpu.io_port[0x0b] = "SIO2_CTRL_B" 76 | 77 | cpu.io_port[0x0c] = "CTC_0_SIOA" 78 | cpu.io_port[0x0d] = "CTC_1_SIOA" 79 | cpu.io_port[0x0e] = "CTC_2_INT_DISP" 80 | cpu.io_port[0x0f] = "CTC_3_INT_FLOP" 81 | 82 | cpu.io_port[0x10] = "PIO_KBD_DATA" 83 | cpu.io_port[0x11] = "PIO_PARALLEL_DATA" 84 | cpu.io_port[0x12] = "PIO_KBD_CTRL" 85 | cpu.io_port[0x13] = "PIO_PARALLEL_CTRL" 86 | 87 | 88 | cpu.io_port[0x14] = ("DIP_SWITCH", "FLOP_MOTOR") 89 | 90 | cpu.io_port[0x18] = "DISABLE_EPROM" 91 | 92 | cpu.io_port[0x1c] = "SOUND" 93 | 94 | for i in range(0xf0, 0x100): 95 | cpu.io_port[i] = "DMA_%02x" % i 96 | 97 | ####################################################################### 98 | 99 | cpu.disass(0) 100 | cpu.disass(0x0027) 101 | 102 | ####################################################################### 103 | # Interrupt vectors 104 | 105 | for i in range(0x7300,0x7320, 2): 106 | da = p.m.l16(i) 107 | cpu.disass(da) 108 | const.w16(p, i) 109 | 110 | ####################################################################### 111 | 112 | while p.run(): 113 | pass 114 | 115 | ####################################################################### 116 | 117 | cpu.to_tree() 118 | 119 | ####################################################################### 120 | 121 | p.setlabel(0x7000, "Error_No_System_Files") 122 | const.txtlen(p, 0x707d, 0x15) 123 | # p.setlabel(0x707d, '"**NO SYSTEM FILES**"') 124 | 125 | ####################################################################### 126 | 127 | p.setlabel(0x701e, "Error_No_Diskette_Nor_Lineprog") 128 | const.txtlen(p, 0x7092, 0x1e) 129 | #p.setlabel(0x7092, '"**NO DISKETTE NOR LINEPROG**"') 130 | 131 | ####################################################################### 132 | 133 | p.setlabel(0x700f, "Error_No_Katalog") 134 | const.txtlen(p, 0x70b0, 0x10) 135 | #p.setlabel(0x70b0, '"**NO KATALOG**"') 136 | 137 | ####################################################################### 138 | 139 | p.setlabel(0x7068, "memcpy(BC,DE,HL)") 140 | p.setlabel(0x70e9, "InitHW") 141 | 142 | ####################################################################### 143 | 144 | x = p.t.add(0x7300, 0x7320, "tbl") 145 | x.blockcmt = """- 146 | Interrupt Vector Table 147 | """ 148 | p.setlabel(0x7300, "IntVectors") 149 | p.setlabel(0x73c6, "IntVecNop") 150 | for i in range(0x7300,0x7320,2): 151 | da = p.m.l16(i) 152 | if da == 0x73c6: 153 | continue 154 | p.setlabel(da, "IntVec%d" % ((i - 0x7300)/2)) 155 | 156 | p.setlabel(0x7362, "INT6") 157 | p.setlabel(0x7770, "INT7") 158 | 159 | ####################################################################### 160 | 161 | p.setlabel(0x73de, "Msg_Diskette_Error") 162 | const.txtlen(p, 0x73f0, 0x13) 163 | 164 | ####################################################################### 165 | const.txtlen(p, 0x7071, 0x06) 166 | ####################################################################### 167 | const.txtlen(p, 0x7077, 0x06) 168 | ####################################################################### 169 | const.txtlen(p, 0x70c3, 0x05) 170 | const.txtlen(p, 0x70c8, 0x05) 171 | 172 | ####################################################################### 173 | # Build code graph 174 | 175 | if True: 176 | p.g = topology.topology(p) 177 | p.g.build_bb() 178 | p.g.segment() 179 | p.g.setlabels(p) 180 | p.g.dump_dot() 181 | p.g.xxx(p) 182 | 183 | ####################################################################### 184 | 185 | if False: 186 | import pseudo 187 | 188 | regs = dict() 189 | regs["rc"] = 1 190 | regs["ra"] = 4 191 | for i in range(0,16): 192 | regs["r%d" %i] = 4 193 | regs["rsrc"] = 8 194 | regs["rdcl"] = 11 195 | 196 | def fbb(tree, priv, lvl): 197 | if tree.tag == "bb": 198 | pseudo.pseudo_test(tree, regs) 199 | 200 | p.t.recurse(fbb) 201 | 202 | ####################################################################### 203 | # Render output 204 | 205 | print("Render") 206 | r = render.render(p) 207 | r.add_flows() 208 | r.render("/tmp/_.z80.txt") 209 | -------------------------------------------------------------------------------- /tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.1 2 | # 3 | # A class which implements a tree of perfectly subsetting ranges 4 | # 5 | # This is used to partition the memory space into logical ranges 6 | # such as "procedure", "statement", "instruction" etc. 7 | # 8 | # The '.a' member is where we put random properties of the nodes 9 | 10 | import bisect 11 | 12 | class TreeError(Exception): 13 | def __init__(self, t1, t2, reason): 14 | self.t1 = t1 15 | self.t2 = t2 16 | self.reason = "%s and %s: %s" % (t1, t2, reason) 17 | def __str__(self): 18 | return self.reason 19 | 20 | class tree(object): 21 | def __init__(self, start, end, tag = "root"): 22 | self.start = start 23 | self.end = end 24 | self.child = list() 25 | self.cend = list() 26 | self.seq = 0 27 | self.a = dict() 28 | self.parent = None 29 | self.tag = tag 30 | self.render = None 31 | self.descend = True 32 | self.cmt = list() 33 | self.blockcmt = "" 34 | self.fold = False 35 | if tag == "root": 36 | self.nseq = 1 37 | 38 | def __str__(self): 39 | return "" % \ 40 | (self.start, self.end, self.tag, self.seq) 41 | 42 | # Recursively descend the tree, and create a new node 43 | # 44 | # 'above' controls behaviour if we encounter an node which has 45 | # the same (start,end) values as we try to insert: 46 | # above == True: become parent 47 | # above == False: become child 48 | # 49 | def add(self, start, end, tag, above=True, t=None): 50 | assert start != end 51 | assert start >= self.start 52 | assert end <= self.end 53 | assert end > start 54 | if t == None: 55 | t = tree(start, end, tag) 56 | if t.seq == 0: 57 | t.seq = self.nseq 58 | self.nseq += 1 59 | i = bisect.bisect(self.cend, start) 60 | j = i 61 | while j < len(self.child): 62 | c = self.child[j] 63 | if c.end <= start: 64 | j += 1 65 | i += 1 66 | continue 67 | if c.start >= end: 68 | break 69 | if c.start == start and c.end == end and above: 70 | pass 71 | elif c.start <= start and c.end >= end: 72 | return c.add(start, end, tag, above, t) 73 | elif c.start < start and c.end < end: 74 | raise TreeError(t, c, "Overlap(1)") 75 | elif c.start > start and c.end > end: 76 | raise TreeError(t, c, "Overlap(2)") 77 | j += 1 78 | k = i 79 | while k < len(self.child): 80 | c = self.child[k] 81 | if c.start >= start and c.end <= end: 82 | t.child.append(c) 83 | t.cend.append(c.end) 84 | del self.child[k] 85 | del self.cend[k] 86 | continue 87 | k += 1 88 | self.child.insert(i, t) 89 | self.cend.insert(i, end) 90 | t.parent = self 91 | return t 92 | 93 | def __fnd(self, start, tag): 94 | for i in self.child: 95 | if i.start == start and i.tag == tag: 96 | return i 97 | if start >= i.start and start <= i.end and len(i.child): 98 | j = i.__fnd(start, tag) 99 | if j != None: 100 | return j 101 | return None 102 | 103 | def find(self, start, tag): 104 | if start < self.start or start >= self.end: 105 | raise TreeError(self, "0x%x" % start, "Out of Bounds") 106 | l = len(self.child) 107 | i = bisect.bisect_right(self.cend, start) 108 | if l == 0 or l == i: 109 | return None 110 | if i < 0 or i >= l: 111 | raise TreeError(self, "0x%x" % start, "Out of Bounds (2)") 112 | x = self.child[i] 113 | if x.start == start and x.tag == tag: 114 | return x 115 | return x.__fnd(start, tag) 116 | 117 | # Return a list of gaps 118 | def gaps(self): 119 | p = self.start 120 | l = list() 121 | for i in self.child: 122 | if p < i.start: 123 | l.append((p, i.start)) 124 | else: 125 | assert p == i.start 126 | p = i.end 127 | if p < self.end: 128 | l.append((p, self.end)) 129 | return l 130 | 131 | def recurse(self, func=None, priv=None, lvl=0): 132 | retval = False 133 | if func == None: 134 | i = " "[0:2*lvl] 135 | s = "%s %s" % (i , self) 136 | for j in self.a: 137 | s += " %s = %s" % (j, self.a[j]) 138 | s += str(self.cmt) 139 | print(s) 140 | 141 | elif func(self, priv, lvl): 142 | retval = True 143 | for i in self.child: 144 | if i.recurse(func, priv, lvl + 1): 145 | retval = True 146 | return retval 147 | 148 | def lcmt(self, s): 149 | if s[-1] == "\n": 150 | self.cmt.append(s[:-1]) 151 | else: 152 | self.cmt.append(s) 153 | 154 | def sanity(self, priv=None, lvl=0): 155 | for i in self.child: 156 | assert i.start >= self.start 157 | assert i.end <= self.end 158 | 159 | if __name__ == "__main__": 160 | 161 | t = tree(0, 1000) 162 | t.find(0, "foo") 163 | t.find(999, "foo") 164 | try: 165 | t.find(1000, "foo") 166 | assert(False) 167 | except: 168 | pass 169 | t.add(100,200, "a") 170 | t.add(100,200, "b") 171 | t.add(100,200, "c", False) 172 | t.add(700,800, "d") 173 | t.add(300,400, "e") 174 | t.add(150,180, "f") 175 | t.add(150,170, "g") 176 | t.add(170,180, "h") 177 | t.add(160,161, "i") 178 | x = t.add(50,550, "j") 179 | try: 180 | x = t.add(50,350, "A") 181 | raise TreeError(t, x, "Should not work") 182 | except: 183 | pass 184 | try: 185 | x = t.add(150,550, "B") 186 | raise TreeError(t, x, "Should not work") 187 | except: 188 | pass 189 | t.recurse() 190 | t.recurse(sanity) 191 | print(t) 192 | print(t.gaps()) 193 | --------------------------------------------------------------------------------