/ emu8051-3102.py
emu8051-3102.py
1 #!/usr/bin/env python3 2 import sys, os 3 from subprocess import PIPE, STDOUT, Popen 4 5 trace = True 6 vm_trace = True 7 8 getc = [ord(c) for c in reversed("5\n23\n42\n13\nY\n")] 9 10 fns = { 11 0x2d92: 'vm_swapAB', 12 0x2e6f: 'vm_storeB@dptr-4', 13 0x2d4c: 'vm_add', 14 0x2d5c: 'vm_sub', 15 0x2d6c: 'vm_umul', 16 0x2dc8: 'vm_mul', 17 0x2d7f: 'vm_udiv', 18 0x2e7c: 'vm_storeB@dptr-4ThenSwapAB', 19 0x2e82: 'vm_mov_b_imm', 20 0x2e99: 'vm_mov_imm_a_and_store@0x7f40', 21 0x3008: 'vm_fn1', 22 0x2ff3: 'vm_fn2', 23 0x306f: 'vm_fn3', 24 0x2d9f: 'vm_abs', 25 0x2f9f: 'getshort2vm_b', 26 0x2f1c: 'print_int_vm_a', 27 0x2f02: 'vm_print', 28 0x2eb8: 'vm_jmp', 29 0x2ea4: 'push_pc++', 30 0x2ef8: 'pop_pc', 31 0x2ec8: 'vm_jz', 32 0x2ecf: 'vm_jnz', 33 0x2ed6: 'vm_jns', 34 0x2edd: 'vm_js'} 35 36 def split_by_n(obj, n): 37 # src https://stackoverflow.com/questions/9475241/split-string-every-nth-character 38 return [obj[i:i+n] for i in range(0, len(obj), n)] 39 40 display = [] 41 def flush_display(): 42 global display 43 if display == []: return 44 if not (trace or vm_trace): 45 print("display:", repr(''.join(display))) 46 display = [] 47 48 class MEM: 49 def __init__(self, mcu, getter, setter): 50 self.mcu = mcu 51 self.getter = getter 52 self.setter = setter 53 54 def __setitem__(self, addr, value): 55 self.mcu.send(f"{self.setter} 0x{addr:x} 0x{value:x}\n".encode("utf8")) 56 57 def __getitem__(self, addr): 58 if isinstance(addr,slice): 59 if addr.step: 60 raise ValueError("step not supported for slicing mem") 61 if not addr.stop: addr.stop = addr.start + 1 62 size = addr.stop - addr.start 63 64 # send cmd 65 msg = f"{self.getter} 0x{addr.start:02x} 0x{size:02x}\n".encode("utf8") 66 return bytes([int(x,16) 67 for line in self.mcu.send(msg,int(((size-1)/16)+1)*72) 68 for x in line[6:53].split()]) 69 70 msg = f"{self.getter} 0x{addr:02x} 1\n".encode("utf8") 71 return int(self.mcu.send(msg,72)[0][6:53].split()[0],16) 72 73 class EMU: 74 def __init__(self): 75 self.mem = MEM(self,"di", "wi") 76 self.xmem = MEM(self,"de", "we") 77 self.rom = MEM(self,"dp", "wp") 78 self.p = Popen(['emu8051/src/cli/emu8051-cli', '-q', '1', 'ROM.hex'], 79 stdin=PIPE, stdout=PIPE, stderr=STDOUT, bufsize=0) 80 _, x = self.read(3) # skip initial prompt 81 self.regs = self.get_regs() 82 83 def read(self, toread): 84 res = [] 85 cur = 0 86 while(cur<toread): 87 #print(sum(len(e) for e in res),toread) 88 buf = os.read(self.p.stdout.fileno(), toread - cur) 89 if not buf: # EOF 90 print('eof') 91 break 92 else: 93 #print(len(buf), repr(buf)) 94 res.append(buf) 95 cur = sum(len(e) for e in res) 96 return sum(len(e) for e in res), [l.strip() for l in b''.join(res).decode('utf8').split('\n')] 97 98 def send(self, msg, expected=None): 99 #print("sending", msg) 100 self.p.stdin.write(msg) 101 size, buf = self.read(len(msg)) 102 if size!=len(msg): 103 buf = ''.join(buf) 104 print('meh', len(buf), repr(buf)) 105 raise ValueError 106 107 if expected: 108 # read hexdump 109 msize, m = self.read(expected) 110 if msize != expected: 111 buf = ''.join(m) 112 print('meh dumpmem', expected, msize, repr(m)) 113 raise ValueError 114 115 size, buf = self.read(3) 116 if size!=3: 117 buf = ''.join(buf) 118 print('meh prompt', len(buf), repr(buf)) 119 raise ValueError 120 #print('sent') 121 122 if expected: 123 return m 124 125 @property 126 def a(self): 127 return self.regs['ACC'] 128 129 @a.setter 130 def a(self, value): 131 self.send((f"wr a 0x{value:02x}\n").encode("utf8")) 132 self.regs['ACC'] = value 133 134 @property 135 def dptr(self): 136 return self.regs['DPTR'] 137 138 @dptr.setter 139 def dptr(self, value): 140 self.send((f"wr dptr 0x{value:04x}\n").encode("utf8")) 141 self.regs['DPTR'] = value 142 143 @property 144 def pc(self): 145 return self.regs['PC'] 146 147 @pc.setter 148 def pc(self, value): 149 self.send((f"wr pc 0x{value:04x}\n").encode("utf8")) 150 self.regs['PC'] = value 151 152 @property 153 def sp(self): 154 return self.regs['SP'] 155 156 @sp.setter 157 def sp(self, value): 158 self.send((f"wr sp 0x{value:04x}\n").encode("utf8")) 159 self.regs['SP'] = value 160 161 @property 162 def r0(self): 163 return self.regs['R0'] 164 165 @r0.setter 166 def r0(self, value): 167 self.send((f"wr r0 0x{value:04x}\n").encode("utf8")) 168 self.regs['R0'] = value 169 170 @property 171 def r1(self): 172 return self.regs['R1'] 173 174 @r1.setter 175 def r1(self, value): 176 self.send((f"wr r1 0x{value:04x}\n").encode("utf8")) 177 self.regs['R1'] = value 178 179 @property 180 def r2(self): 181 return self.regs['R2'] 182 183 @r2.setter 184 def r2(self, value): 185 self.send((f"wr r2 0x{value:04x}\n").encode("utf8")) 186 self.regs['R2'] = value 187 188 def disasm_pc(self): 189 msg = (f"u 0x{self.pc:04x} 1\n").encode("utf8") 190 self.p.stdin.write(msg) 191 size, buf = self.read(len(msg)) 192 if size!=len(msg): 193 buf = ''.join(buf) 194 print('meh', len(buf), repr(buf)) 195 raise ValueError 196 197 m = self.p.stdout.readline().strip().decode('utf8') 198 199 size, buf = self.read(3) 200 if size!=3: 201 buf = ''.join(buf) 202 print('meh prompt', len(buf), repr(buf)) 203 raise ValueError 204 205 addr, asm, op = m.split(" ",2) 206 return int(addr,16), tuple(int(x,16) for x in asm.split()), ' '.join(op.split()) 207 208 def get_regs(self): 209 # send cmd 210 msg = b'dr\n' 211 b = self.send(b'dr\n',590) 212 if b[0] != '-' * 70: return 213 res = {} 214 for r, v in (zip(b[1].split('|')+b[4].split('|'), b[2].split('|')+b[5].split('|'))): 215 r = r.strip() 216 v = v.strip() 217 if (r,v) == ('',''): continue 218 if not r.startswith("PSW:"): res[r] = int(v,16) 219 else: res['CY']=int(v[0]) 220 return res 221 222 def next_cycle(self): 223 self.send(b"s\n") 224 self.regs = self.get_regs() 225 226 def quit(self): 227 self.send(b"q\n") 228 return self.p.wait() 229 230 def ret(self): 231 self.pc = (mcu.mem[(mcu.sp)] << 8) | mcu.mem[mcu.sp - 1] 232 self.sp -= 2 233 234 def run(mcu, end_addr): 235 i = 0 236 while mcu.pc != end_addr: 237 i+=1 238 if vm_trace and int(mcu.pc) in fns: 239 #flush_display() 240 vm_op = fns[int(mcu.pc)] 241 vm_addr = int(mcu.mem[0x32]) << 8 | int(mcu.mem[0x33]) 242 print(f"\033[92mv {vm_addr-1:04x} {vm_op}", end="") 243 if vm_op in {"vm_add", "vm_sub", "vm_mul", "vm_udiv", "vm_umul", "vm_swapAB"}: 244 a = (int(mcu.mem[0x2a]) << 24 | int(mcu.mem[0x2b]) << 16 | int(mcu.mem[0x2c]) << 8 | int(mcu.mem[0x2d])) 245 b = (int(mcu.mem[0x2e]) << 24 | int(mcu.mem[0x2f]) << 16 | int(mcu.mem[0x30]) << 8 | int(mcu.mem[0x31])) 246 print(f"({a:08x}, {b:08x})", end="") 247 elif vm_op in {"vm_abs", "vm_jns", 'vm_jmp', 'vm_jz', 'vm_jnz', 'vm_jns', 'vm_js'}: 248 b = (int(mcu.mem[0x2e]) << 24 | int(mcu.mem[0x2f]) << 16 | int(mcu.mem[0x30]) << 8 | int(mcu.mem[0x31])) 249 print(f"({b:08x})", end="") 250 elif vm_op in {"vm_storeB@dptr-4", 'vm_storeB@dptr-4ThenSwapAB'}: 251 b = (int(mcu.mem[0x2e]) << 24 | int(mcu.mem[0x2f]) << 16 | int(mcu.mem[0x30]) << 8 | int(mcu.mem[0x31])) 252 print(f"({int(mcu.dptr)-4:04x}, {b:08x}", end="") 253 elif vm_op in {"vm_mov_imm_a_and_store@0x7f40", "vm_mov_b_imm"}: 254 tmp = (int(mcu.rom[vm_addr]) << 24 | int(mcu.rom[vm_addr+1]) << 16 | int(mcu.rom[vm_addr+2]) << 8 | int(mcu.rom[vm_addr+3])) 255 print(f"({tmp:08x})", end="") 256 elif vm_op == "vm_print": 257 txt = [] 258 idx = 0 259 while not (mcu.rom[vm_addr+idx] & 0x80): 260 txt.append(chr(mcu.rom[vm_addr+idx])) 261 idx+=1 262 txt.append(chr(mcu.rom[vm_addr+idx] & 0x7f)) 263 print(f"({repr(''.join(txt))})", end="") 264 print("\033[00m") 265 266 if vm_trace: 267 if int(mcu.pc) == 0x2ce9: 268 flush_display() 269 print("loading 0x2e from offset:", hex(int(mcu.a)), end='\n' if trace else ' ') 270 elif int(mcu.pc) == 0x2cfb: 271 flush_display() 272 print("value", hex(int(mcu.mem[0x2e]) << 24 | int(mcu.mem[0x2f]) << 16 | int(mcu.mem[0x30]) << 8 | int(mcu.mem[0x31]))) 273 274 #op = Operation(mcu.rom[int(mcu.pc)]) 275 #op.args = mcu.rom[int(mcu.pc + 1):int(mcu.pc + len(op))] 276 pc, asm, op = mcu.disasm_pc() 277 if trace: 278 flush_display() 279 a = (int(mcu.mem[0x2a]) << 24 | int(mcu.mem[0x2b]) << 16 | int(mcu.mem[0x2c]) << 8 | int(mcu.mem[0x2d])) 280 b = (int(mcu.mem[0x2e]) << 24 | int(mcu.mem[0x2f]) << 16 | int(mcu.mem[0x30]) << 8 | int(mcu.mem[0x31])) 281 print(f"i {int(mcu.pc):04x} {str(op):<30} | " 282 f"{int(mcu.a):02x} " 283 f"{int(mcu.r0):02x} " 284 f"{int(mcu.r1):02x} " 285 f"{int(mcu.r2):02x} " 286 f"{int(mcu.dptr):04x} " 287 f"{int(mcu.mem[0xd0]) & 0xfe:02x} " 288 f"{int(mcu.mem[0xd1]):02x} " 289 f"{a:08x} {b:08x}") 290 if i == 25665: 291 print(f"{mcu.mem[mcu.r0]:02x}") 292 293 if asm[0] == 0x12: # lcall 294 if asm[1:] == (0x03,0x7a): # putc 295 if trace: 296 print(f"putc({repr(chr(int(mcu.a)))})") 297 mcu.pc += len(asm) 298 #print(f"{chr(int(mcu.a))}", end='') 299 display.append(chr(int(mcu.a))) 300 continue 301 elif asm[1:] == (0x05,0x65): # getc 302 if trace: 303 flush_display() 304 print("getc()") 305 mcu.pc += len(asm) 306 #mcu.a = ord(input('')[0]) 307 mcu.a = getc.pop() 308 continue 309 elif asm[0] == 0x2: # jmp 310 if asm[1:] == (0x03,0x7a): # putc 311 if trace: 312 print(f"putc({repr(chr(int(mcu.a)))})") 313 #print(f"{chr(int(mcu.a))}", end='') 314 display.append(chr(int(mcu.a))) 315 mcu.ret() # ret 316 continue 317 elif asm[1:] == (0x05,0x65): # getc 318 if trace: 319 flush_display() 320 print("getc()") 321 #mcu.a = ord(input('')[0]) 322 mcu.a = getc.pop() 323 mcu.ret() # ret 324 continue 325 mcu.next_cycle() 326 if trace: 327 flush_display() 328 print("end, total insn", i) 329 return i 330 331 mcu = EMU() 332 333 mcu.mem[0x25] = 0 334 mcu.mem[0x2a] = 64 335 mcu.mem[0x2b] = 0 336 mcu.mem[0x2c] = 127 337 mcu.mem[0x2d] = 0 338 mcu.mem[0x2e] = 0 339 mcu.mem[0x2f] = 0 340 mcu.mem[0x30] = 0 341 mcu.mem[0x31] = 0 342 343 mcu.xmem[0x7f00] = 0xde 344 mcu.xmem[0x7f01] = 0xad 345 mcu.xmem[0x7f02] = 0xbe 346 mcu.xmem[0x7f03] = 0xef 347 348 mcu.xmem[0x7f04] = 0x13 349 mcu.xmem[0x7f05] = 0x37 350 mcu.xmem[0x7f06] = 0xc0 351 mcu.xmem[0x7f07] = 0xde 352 353 mcu.xmem[0x7f08] = 0xac 354 mcu.xmem[0x7f09] = 0xad 355 mcu.xmem[0x7f0a] = 0xea 356 mcu.xmem[0x7f0b] = 0xdb 357 358 mcu.xmem[0x7f0c] = 0xc0 359 mcu.xmem[0x7f0d] = 0x01 360 mcu.xmem[0x7f0e] = 0xba 361 mcu.xmem[0x7f0f] = 0xbe 362 363 mcu.xmem[0x7f1c] = 0x1c 364 mcu.xmem[0x7f1d] = 0x7f 365 mcu.xmem[0x7f1e] = 0x7f 366 mcu.xmem[0x7f1f] = 0x1c 367 368 mcu.xmem[0x7f30] = 0x30 369 mcu.xmem[0x7f31] = 0x7f 370 mcu.xmem[0x7f32] = 0x7f 371 mcu.xmem[0x7f33] = 0x30 372 373 mcu.xmem[0x7f34] = 0x34 374 mcu.xmem[0x7f35] = 0x7f 375 mcu.xmem[0x7f36] = 0x7f 376 mcu.xmem[0x7f37] = 0x34 377 378 mcu.xmem[0x7f38] = 0x38 379 mcu.xmem[0x7f39] = 0x7f 380 mcu.xmem[0x7f3a] = 0x7f 381 mcu.xmem[0x7f3b] = 0x38 382 383 mcu.xmem[0x7f3c] = 0x3c 384 mcu.xmem[0x7f3d] = 0x7f 385 mcu.xmem[0x7f3e] = 0x7f 386 mcu.xmem[0x7f3f] = 0x3c 387 388 mcu.pc = 0x3102 389 steps = run(mcu, 0x64f)