| """ |
| x86_core.py -- i386/i486 user-mode integer core (flat 32-bit protected mode), |
| every data transformation routed through the x86_units API (golden or neural). |
| |
| Scope: the instruction set a -march=i486 -O1 musl/doomgeneric binary uses. |
| No FPU (DOOM is fixed-point), no paging (flat), no real mode. Segments are |
| flat except %gs, whose base is honored for i386 TLS. |
| |
| Composition stances (consistent with the GB bricks): |
| - all arithmetic/logic/shift/mul/div through verified slice units (ALU class) |
| - effective-address arithmetic, immediate assembly, and dispatch are wiring |
| - one-operand IMUL/MUL produce edx:eax via the 8x8 partial-product tree; |
| IDIV/DIV are restoring division over verified subtract slices |
| """ |
| from x86_units import GoldenUnits, ALU |
|
|
| EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI = range(8) |
| CF, PF, AF, ZF, SF, OF, DF = "CF", "PF", "AF", "ZF", "SF", "OF", "DF" |
| M32 = 0xFFFFFFFF |
|
|
|
|
| def sx8(v): return v - 0x100 if v & 0x80 else v |
| def sx16(v): return v - 0x10000 if v & 0x8000 else v |
| def sx32(v): return v - 0x100000000 if v & 0x80000000 else v |
|
|
|
|
| class CPUError(Exception): |
| pass |
|
|
|
|
| class X86: |
| def __init__(self, mem, units=None): |
| self.mem = mem |
| self.u = units or GoldenUnits() |
| self.alu = ALU(self.u) |
| self.r = [0] * 8 |
| self.eip = 0 |
| self.f = {CF: 0, PF: 0, AF: 0, ZF: 0, SF: 0, OF: 0, DF: 0} |
| self.gs_base = 0 |
| self.exited = None |
| self.syscall = None |
| self.instr_count = 0 |
|
|
| |
| def rd(self, a, n): |
| a &= M32 |
| return int.from_bytes(self.mem[a:a + n], "little") |
| def wr(self, a, v, n): |
| a &= M32 |
| self.mem[a:a + n] = int(v & ((1 << (8 * n)) - 1)).to_bytes(n, "little") |
|
|
| def fetch(self, n=1): |
| v = self.rd(self.eip, n) |
| self.eip = (self.eip + n) & M32 |
| return v |
|
|
| |
| def get_r(self, i, size): |
| if size == 32: return self.r[i] |
| if size == 16: return self.r[i] & 0xFFFF |
| if i < 4: return self.r[i] & 0xFF |
| return (self.r[i - 4] >> 8) & 0xFF |
| def set_r(self, i, v, size): |
| if size == 32: self.r[i] = v & M32 |
| elif size == 16: self.r[i] = (self.r[i] & 0xFFFF0000) | (v & 0xFFFF) |
| elif i < 4: self.r[i] = (self.r[i] & ~0xFF) | (v & 0xFF) |
| else: self.r[i - 4] = (self.r[i - 4] & ~0xFF00) | ((v & 0xFF) << 8) |
|
|
| |
| def setf(self, fl): |
| for k, v in fl.items(): |
| self.f[k] = int(v) |
| def eflags(self): |
| f = self.f |
| return (f[CF] | (f[PF] << 2) | (f[AF] << 4) | (f[ZF] << 6) | (f[SF] << 7) |
| | (f[DF] << 10) | (f[OF] << 11) | 0x2) |
| def set_eflags(self, v): |
| self.f[CF] = v & 1; self.f[PF] = (v >> 2) & 1; self.f[AF] = (v >> 4) & 1 |
| self.f[ZF] = (v >> 6) & 1; self.f[SF] = (v >> 7) & 1 |
| self.f[DF] = (v >> 10) & 1; self.f[OF] = (v >> 11) & 1 |
|
|
| def cond(self, cc): |
| f = self.f |
| v = [f[OF], f[CF], f[ZF], f[CF] | f[ZF], f[SF], f[PF], |
| f[SF] ^ f[OF], (f[SF] ^ f[OF]) | f[ZF]][cc >> 1] |
| return v ^ (cc & 1) |
|
|
| |
| def modrm(self, size, seg_base=0): |
| mod, reg, rm = self.u.modrm(self.fetch()) |
| if mod == 3: |
| return reg, ("r", rm) |
| if rm == 4: |
| ss, idx, base = self.u.sib(self.fetch()) |
| ea = 0 if (base == 5 and mod == 0) else self.r[base] |
| if base == 5 and mod == 0: |
| ea = self.fetch(4) |
| if idx != 4: |
| ea = (ea + (self.r[idx] << ss)) & M32 |
| elif rm == 5 and mod == 0: |
| ea = self.fetch(4) |
| else: |
| ea = self.r[rm] |
| if mod == 1: ea = (ea + sx8(self.fetch())) & M32 |
| elif mod == 2: ea = (ea + self.fetch(4)) & M32 |
| return reg, ("m", (ea + seg_base) & M32) |
|
|
| def get_rm(self, loc, size): |
| k, x = loc |
| return self.get_r(x, size) if k == "r" else self.rd(x, size // 8) |
| def set_rm(self, loc, v, size): |
| k, x = loc |
| if k == "r": self.set_r(x, v, size) |
| else: self.wr(x, v, size // 8) |
|
|
| |
| def alu_op(self, op, a, b, size): |
| """op: 0 ADD,1 OR,2 ADC,3 SBB,4 AND,5 SUB,6 XOR,7 CMP. Returns result or None.""" |
| if op == 0: r, fl = self.alu.addsub(0, a, b, size) |
| elif op == 2: r, fl = self.alu.addsub(0, a, b, size, self.f[CF]) |
| elif op in (5, 7): r, fl = self.alu.addsub(1, a, b, size) |
| elif op == 3: r, fl = self.alu.addsub(1, a, b, size, self.f[CF]) |
| elif op == 1: r, fl = self.alu.logic("OR", a, b, size) |
| elif op == 4: r, fl = self.alu.logic("AND", a, b, size) |
| else: r, fl = self.alu.logic("XOR", a, b, size) |
| self.setf(fl) |
| return None if op == 7 else r |
|
|
| def incdec(self, v, size, dec): |
| r, fl = self.alu.addsub(dec, v, 1, size) |
| fl.pop("CF") |
| self.setf(fl) |
| return r |
|
|
| |
| def shift(self, kind, v, count, size): |
| count &= 31 |
| if count == 0: |
| return v |
| msb = 1 << (size - 1) |
| orig_msb = 1 if v & msb else 0 |
| for i in range(count): |
| if kind == 4: |
| v, c = self.alu.shl1(v, size) |
| elif kind == 5: |
| v, c = self.alu.shr1(v, size) |
| elif kind == 7: |
| v, c = self.alu.shr1(v, size, top=1 if v & msb else 0) |
| elif kind == 0: |
| v, c = self.alu.shl1(v, size) |
| if c: v |= 1 |
| elif kind == 1: |
| v, c = self.alu.shr1(v, size, top=v & 1) |
| elif kind == 2: |
| v, nc = self.alu.shl1(v, size) |
| if self.f[CF]: v |= 1 |
| c = nc |
| else: |
| v, c = self.alu.shr1(v, size, top=self.f[CF]) |
| self.f[CF] = c |
| if kind in (4, 5, 7): |
| SF_, ZF_, PF_ = self.alu.flags_of(v, size) |
| self.f[SF], self.f[ZF], self.f[PF] = SF_, ZF_, PF_ |
| if count == 1: |
| if kind == 4: self.f[OF] = ((v >> (size - 1)) & 1) ^ self.f[CF] |
| elif kind == 5: self.f[OF] = orig_msb |
| elif kind == 7: self.f[OF] = 0 |
| elif kind == 0: self.f[OF] = ((v >> (size - 1)) & 1) ^ self.f[CF] |
| elif kind == 1: self.f[OF] = ((v >> (size - 1)) ^ (v >> (size - 2))) & 1 |
| return v |
|
|
| def shd(self, left, v, fill, count, size): |
| """SHLD/SHRD: double shift through verified 1-bit slices over 2*size bits.""" |
| count &= 31 |
| if count == 0: |
| return v |
| if left: |
| wide = (v << size) | fill |
| for _ in range(count): |
| wide, c = ALU.shl1(self.alu, wide, 2 * size) if False else self.alu.shl1(wide, 2 * size) |
| self.f[CF] = c |
| v = (wide >> size) & ((1 << size) - 1) |
| else: |
| wide = (fill << size) | v |
| for _ in range(count): |
| wide, c = self.alu.shr1(wide, 2 * size) |
| self.f[CF] = c |
| v = wide & ((1 << size) - 1) |
| SF_, ZF_, PF_ = self.alu.flags_of(v, size) |
| self.f[SF], self.f[ZF], self.f[PF] = SF_, ZF_, PF_ |
| return v |
|
|
| |
| def push(self, v): |
| self.r[ESP] = (self.r[ESP] - 4) & M32 |
| self.wr(self.r[ESP], v, 4) |
| def pop(self): |
| v = self.rd(self.r[ESP], 4) |
| self.r[ESP] = (self.r[ESP] + 4) & M32 |
| return v |
|
|
| |
| def step(self): |
| self.instr_count += 1 |
| start = self.eip |
| osize = 32; seg = 0 |
| |
| rep = None |
| while True: |
| b = self.rd(self.eip, 1) |
| isp, cls = self.u.prefix(b) |
| if not isp: |
| break |
| self.eip = (self.eip + 1) & M32 |
| if cls == 1: osize = 16 |
| elif cls == 4: rep = "ne" |
| elif cls == 5: rep = "e" |
| elif cls == 6 and b == 0x65: seg = self.gs_base |
| op = self.fetch() |
| try: |
| self.exec_op(op, osize, seg, rep) |
| except CPUError: |
| self.eip = start |
| raise |
|
|
| def exec_op(self, op, osize, seg, rep): |
| S = osize |
| |
| if op < 0x40 and (op & 7) < 6: |
| kind = op >> 3 |
| form = op & 7 |
| if form in (0, 1): |
| size = 8 if form == 0 else S |
| reg, loc = self.modrm(size, seg) |
| r = self.alu_op(kind, self.get_rm(loc, size), self.get_r(reg, size), size) |
| if r is not None: self.set_rm(loc, r, size) |
| elif form in (2, 3): |
| size = 8 if form == 2 else S |
| reg, loc = self.modrm(size, seg) |
| r = self.alu_op(kind, self.get_r(reg, size), self.get_rm(loc, size), size) |
| if r is not None: self.set_r(reg, r, size) |
| else: |
| size = 8 if form == 4 else S |
| imm = self.fetch(size // 8) |
| r = self.alu_op(kind, self.get_r(EAX, size), imm, size) |
| if r is not None: self.set_r(EAX, r, size) |
| return |
| |
| if 0x40 <= op <= 0x4F: |
| i = op & 7 |
| self.set_r(i, self.incdec(self.get_r(i, S), S, (op >> 3) & 1), S) |
| return |
| |
| if 0x50 <= op <= 0x57: self.push(self.get_r(op & 7, 32)); return |
| if 0x58 <= op <= 0x5F: self.set_r(op & 7, self.pop(), 32); return |
| if op == 0x68: self.push(self.fetch(4)); return |
| if op == 0x6A: self.push(sx8(self.fetch()) & M32); return |
| if op == 0x8F: |
| _, loc = self.modrm(S, seg); self.set_rm(loc, self.pop(), 32); return |
| |
| if op in (0x69, 0x6B): |
| reg, loc = self.modrm(S, seg) |
| a = sx32(self.get_rm(loc, S)) if S == 32 else sx16(self.get_rm(loc, S)) |
| b = sx8(self.fetch()) if op == 0x6B else ( |
| sx32(self.fetch(4)) if S == 32 else sx16(self.fetch(2))) |
| full = self.alu.mul(abs(a), abs(b), S) |
| if (a < 0) != (b < 0): full = (-full) & ((1 << (2 * S)) - 1) |
| res = full & ((1 << S) - 1) |
| sres = sx32(res) if S == 32 else sx16(res) |
| ovf = int(sx32(full if S == 32 else 0) != a * b) if S == 32 else 0 |
| ovf = int(((full ^ ((res >> (S-1)) * ((1 << (2*S)) - (1 << S)))) >> S) != 0) |
| self.f[CF] = self.f[OF] = ovf |
| self.set_r(reg, res, S) |
| return |
| |
| if 0x70 <= op <= 0x7F: |
| d = sx8(self.fetch()) |
| if self.cond(op & 0xF): self.eip = (self.eip + d) & M32 |
| return |
| |
| if op in (0x80, 0x81, 0x83): |
| size = 8 if op == 0x80 else S |
| reg, loc = self.modrm(size, seg) |
| imm = (self.fetch() if op == 0x80 else |
| sx8(self.fetch()) & ((1 << size) - 1) if op == 0x83 else |
| self.fetch(size // 8)) |
| r = self.alu_op(reg, self.get_rm(loc, size), imm, size) |
| if r is not None: self.set_rm(loc, r, size) |
| return |
| |
| if op in (0x84, 0x85): |
| size = 8 if op == 0x84 else S |
| reg, loc = self.modrm(size, seg) |
| self.alu_op(4, self.get_rm(loc, size), self.get_r(reg, size), size) |
| return |
| |
| if op in (0x86, 0x87): |
| size = 8 if op == 0x86 else S |
| reg, loc = self.modrm(size, seg) |
| a, b = self.get_rm(loc, size), self.get_r(reg, size) |
| self.set_rm(loc, b, size); self.set_r(reg, a, size) |
| return |
| |
| if 0x88 <= op <= 0x8B: |
| size = 8 if op in (0x88, 0x8A) else S |
| reg, loc = self.modrm(size, seg) |
| if op <= 0x89: self.set_rm(loc, self.get_r(reg, size), size) |
| else: self.set_r(reg, self.get_rm(loc, size), size) |
| return |
| if op in (0x8C, 0x8E): |
| _, loc = self.modrm(16, seg) |
| if op == 0x8C: self.set_rm(loc, 0, 16) |
| return |
| if op == 0x8D: |
| reg, loc = self.modrm(S, seg) |
| assert loc[0] == "m" |
| self.set_r(reg, loc[1], S) |
| return |
| if op == 0x90: return |
| if 0x91 <= op <= 0x97: |
| i = op & 7 |
| a = self.get_r(EAX, S); self.set_r(EAX, self.get_r(i, S), S); self.set_r(i, a, S) |
| return |
| if op == 0x98: |
| self.set_r(EAX, sx16(self.get_r(EAX, 16)) & M32, 32); return |
| if op == 0x99: |
| self.set_r(EDX, (M32 if self.r[EAX] & 0x80000000 else 0), 32); return |
| if op == 0x9C: self.push(self.eflags()); return |
| if op == 0x9D: self.set_eflags(self.pop()); return |
| |
| if op in (0xA0, 0xA1): |
| a = self.fetch(4) + seg |
| self.set_r(EAX, self.rd(a, 1 if op == 0xA0 else S // 8), 8 if op == 0xA0 else S) |
| return |
| if op in (0xA2, 0xA3): |
| a = self.fetch(4) + seg |
| self.wr(a, self.get_r(EAX, 8 if op == 0xA2 else S), 1 if op == 0xA2 else S // 8) |
| return |
| |
| if op in (0xA4, 0xA5, 0xAA, 0xAB, 0xA6, 0xA7, 0xAE, 0xAF, 0xAC, 0xAD): |
| self.string_op(op, S, rep) |
| return |
| if op in (0xA8, 0xA9): |
| size = 8 if op == 0xA8 else S |
| self.alu_op(4, self.get_r(EAX, size), self.fetch(size // 8), size) |
| return |
| |
| if 0xB0 <= op <= 0xB7: self.set_r(op & 7, self.fetch(), 8); return |
| if 0xB8 <= op <= 0xBF: self.set_r(op & 7, self.fetch(S // 8), S); return |
| |
| if op in (0xC0, 0xC1, 0xD0, 0xD1, 0xD2, 0xD3): |
| size = 8 if op in (0xC0, 0xD0, 0xD2) else S |
| kind, loc = self.modrm(size, seg) |
| cnt = (self.fetch() if op in (0xC0, 0xC1) else |
| 1 if op in (0xD0, 0xD1) else self.get_r(ECX, 8)) |
| self.set_rm(loc, self.shift(kind, self.get_rm(loc, size), cnt, size), size) |
| return |
| if op == 0xC2: |
| n = self.fetch(2); self.eip = self.pop() |
| self.r[ESP] = (self.r[ESP] + n) & M32; return |
| if op == 0xC3: self.eip = self.pop(); return |
| if op in (0xC6, 0xC7): |
| size = 8 if op == 0xC6 else S |
| _, loc = self.modrm(size, seg) |
| self.set_rm(loc, self.fetch(size // 8), size) |
| return |
| if op == 0xC9: |
| self.r[ESP] = self.r[EBP]; self.r[EBP] = self.pop(); return |
| if op == 0xCD: |
| n = self.fetch() |
| if n == 0x80 and self.syscall: |
| self.syscall(self) |
| return |
| raise CPUError(f"INT {n:#x}") |
| |
| if op in (0xF6, 0xF7): |
| size = 8 if op == 0xF6 else S |
| kind, loc = self.modrm(size, seg) |
| v = self.get_rm(loc, size) |
| if kind in (0, 1): |
| self.alu_op(4, v, self.fetch(size // 8), size) |
| elif kind == 2: |
| self.set_rm(loc, self.alu.not_(v, size), size) |
| elif kind == 3: |
| r, fl = self.alu.addsub(1, 0, v, size) |
| self.setf(fl); self.set_rm(loc, r, size) |
| else: |
| self.muldiv(kind, v, size) |
| return |
| if op == 0xF8: self.f[CF] = 0; return |
| if op == 0xF9: self.f[CF] = 1; return |
| if op == 0xFC: self.f[DF] = 0; return |
| if op == 0xFD: self.f[DF] = 1; return |
| |
| if op in (0xFE, 0xFF): |
| size = 8 if op == 0xFE else S |
| kind, loc = self.modrm(size, seg) |
| if kind in (0, 1): |
| self.set_rm(loc, self.incdec(self.get_rm(loc, size), size, kind), size) |
| elif kind == 2: self.push(self.eip); self.eip = self.get_rm(loc, 32) |
| elif kind == 4: self.eip = self.get_rm(loc, 32) |
| elif kind == 6: self.push(self.get_rm(loc, 32)) |
| else: raise CPUError(f"FF/{kind}") |
| return |
| if op == 0xE8: |
| d = sx32(self.fetch(4)); self.push(self.eip) |
| self.eip = (self.eip + d) & M32; return |
| if op == 0xE9: |
| d = sx32(self.fetch(4)); self.eip = (self.eip + d) & M32; return |
| if op == 0xEB: |
| d = sx8(self.fetch()); self.eip = (self.eip + d) & M32; return |
| |
| if op == 0x0F: |
| self.exec_0f(self.fetch(), S, seg) |
| return |
| raise CPUError(f"opcode {op:#04x}") |
|
|
| def exec_0f(self, op, S, seg): |
| if 0x80 <= op <= 0x8F: |
| d = sx32(self.fetch(4)) |
| if self.cond(op & 0xF): self.eip = (self.eip + d) & M32 |
| return |
| if 0x90 <= op <= 0x9F: |
| _, loc = self.modrm(8, seg) |
| self.set_rm(loc, 1 if self.cond(op & 0xF) else 0, 8) |
| return |
| if op in (0xB6, 0xB7, 0xBE, 0xBF): |
| ssize = 8 if op in (0xB6, 0xBE) else 16 |
| reg, loc = self.modrm(ssize, seg) |
| v = self.get_rm(loc, ssize) |
| if op >= 0xBE: |
| v = (sx8(v) if ssize == 8 else sx16(v)) & M32 |
| self.set_r(reg, v, S) |
| return |
| if op == 0xAF: |
| reg, loc = self.modrm(S, seg) |
| a = sx32(self.get_r(reg, S)); b = sx32(self.get_rm(loc, S)) |
| full = self.alu.mul(abs(a), abs(b), S) |
| if (a < 0) != (b < 0): full = (-full) & ((1 << (2 * S)) - 1) |
| res = full & M32 |
| self.f[CF] = self.f[OF] = int(sx32(res) != a * b) |
| self.set_r(reg, res, S) |
| return |
| if op in (0xA4, 0xA5): |
| reg, loc = self.modrm(S, seg) |
| cnt = self.fetch() if op == 0xA4 else self.get_r(ECX, 8) |
| self.set_rm(loc, self.shd(1, self.get_rm(loc, S), self.get_r(reg, S), cnt, S), S) |
| return |
| if op in (0xAC, 0xAD): |
| reg, loc = self.modrm(S, seg) |
| cnt = self.fetch() if op == 0xAC else self.get_r(ECX, 8) |
| self.set_rm(loc, self.shd(0, self.get_rm(loc, S), self.get_r(reg, S), cnt, S), S) |
| return |
| if op == 0xBC or op == 0xBD: |
| reg, loc = self.modrm(S, seg) |
| v = self.get_rm(loc, S) |
| self.f[ZF] = int(v == 0) |
| if v: |
| idx = (v & -v).bit_length() - 1 if op == 0xBC else v.bit_length() - 1 |
| self.set_r(reg, idx, S) |
| return |
| if op == 0xA3 or op == 0xAB or op == 0xB3 or op == 0xBA: |
| if op == 0xBA: |
| kind, loc = self.modrm(S, seg) |
| bit = self.fetch() & (S - 1) |
| else: |
| reg, loc = self.modrm(S, seg) |
| bit = self.get_r(reg, S) & (S - 1) |
| kind = {0xA3: 4, 0xAB: 5, 0xB3: 6}[op] |
| v = self.get_rm(loc, S) |
| self.f[CF] = (v >> bit) & 1 |
| if kind == 5: self.set_rm(loc, v | (1 << bit), S) |
| elif kind == 6: self.set_rm(loc, v & ~(1 << bit), S) |
| return |
| if op in (0xB0, 0xB1): |
| size = 8 if op == 0xB0 else S |
| reg, loc = self.modrm(size, seg) |
| dst = self.get_rm(loc, size); acc = self.get_r(EAX, size) |
| self.alu_op(7, acc, dst, size) |
| if self.f[ZF]: |
| self.set_rm(loc, self.get_r(reg, size), size) |
| else: |
| self.set_r(EAX, dst, size) |
| return |
| if op in (0xC0, 0xC1): |
| size = 8 if op == 0xC0 else S |
| reg, loc = self.modrm(size, seg) |
| a, b = self.get_rm(loc, size), self.get_r(reg, size) |
| r = self.alu_op(0, a, b, size) |
| self.set_r(reg, a, size); self.set_rm(loc, r, size) |
| return |
| if 0xC8 <= op <= 0xCF: |
| i = op & 7; v = self.r[i] |
| self.r[i] = int.from_bytes(v.to_bytes(4, "little"), "big") |
| return |
| if op == 0xA2: |
| self.r[EAX] = self.r[EBX] = self.r[ECX] = self.r[EDX] = 0 |
| return |
| if 0x40 <= op <= 0x4F: |
| reg, loc = self.modrm(S, seg) |
| v = self.get_rm(loc, S) |
| if self.cond(op & 0xF): self.set_r(reg, v, S) |
| return |
| raise CPUError(f"0F {op:#04x}") |
|
|
| |
| def muldiv(self, kind, v, size): |
| a = self.get_r(EAX, size) |
| if kind == 4: |
| full = self.alu.mul(a, v, size) |
| lo = full & ((1 << size) - 1); hi = full >> size |
| self.set_r(EAX, lo, size) |
| if size == 8: self.set_r(EAX, full, 16) |
| else: self.set_r(EDX, hi, size) |
| self.f[CF] = self.f[OF] = int(hi != 0) |
| elif kind == 5: |
| sa = sx8(a) if size == 8 else sx16(a) if size == 16 else sx32(a) |
| sv = sx8(v) if size == 8 else sx16(v) if size == 16 else sx32(v) |
| full = self.alu.mul(abs(sa), abs(sv), size) |
| if (sa < 0) != (sv < 0): full = (-full) & ((1 << (2 * size)) - 1) |
| lo = full & ((1 << size) - 1); hi = full >> size |
| if size == 8: self.set_r(EAX, full, 16) |
| else: self.set_r(EAX, lo, size); self.set_r(EDX, hi, size) |
| sign_ext = ((1 << size) - 1) if lo >> (size - 1) else 0 |
| self.f[CF] = self.f[OF] = int(hi != sign_ext) |
| else: |
| if size == 8: |
| num = self.get_r(EAX, 16) |
| else: |
| num = (self.get_r(EDX, size) << size) | a |
| if kind == 6: |
| q, r = self.alu.divmod_(num, v, 2 * size) |
| if q >= (1 << size): raise CPUError("#DE overflow") |
| else: |
| bits2 = 2 * size |
| snum = num - (1 << bits2) if num >> (bits2 - 1) else num |
| sden = sx8(v) if size == 8 else sx16(v) if size == 16 else sx32(v) |
| q0, r0 = self.alu.divmod_(abs(snum), abs(sden), bits2) |
| q = -q0 if (snum < 0) != (sden < 0) else q0 |
| r = -r0 if snum < 0 else r0 |
| if not (-(1 << (size - 1)) <= q < (1 << (size - 1))): |
| raise CPUError("#DE overflow") |
| q &= (1 << size) - 1; r &= (1 << size) - 1 |
| if size == 8: |
| self.set_r(EAX, q, 8); self.set_r(4, r, 8) |
| else: |
| self.set_r(EAX, q, size); self.set_r(EDX, r, size) |
|
|
| |
| def string_op(self, op, S, rep): |
| size = 8 if op in (0xA4, 0xAA, 0xA6, 0xAE, 0xAC) else S |
| n = size // 8 |
| step = -n if self.f[DF] else n |
| def one(): |
| si, di = self.r[ESI], self.r[EDI] |
| if op in (0xA4, 0xA5): |
| self.wr(di, self.rd(si, n), n) |
| self.r[ESI] = (si + step) & M32; self.r[EDI] = (di + step) & M32 |
| elif op in (0xAA, 0xAB): |
| self.wr(di, self.get_r(EAX, size), n) |
| self.r[EDI] = (di + step) & M32 |
| elif op in (0xAC, 0xAD): |
| self.set_r(EAX, self.rd(si, n), size) |
| self.r[ESI] = (si + step) & M32 |
| elif op in (0xA6, 0xA7): |
| self.alu_op(7, self.rd(si, n), self.rd(di, n), size) |
| self.r[ESI] = (si + step) & M32; self.r[EDI] = (di + step) & M32 |
| else: |
| self.alu_op(7, self.get_r(EAX, size), self.rd(di, n), size) |
| self.r[EDI] = (di + step) & M32 |
| if rep is None: |
| one(); return |
| cmp_op = op in (0xA6, 0xA7, 0xAE, 0xAF) |
| while self.r[ECX]: |
| one() |
| self.r[ECX] = (self.r[ECX] - 1) & M32 |
| if cmp_op: |
| if rep == "e" and not self.f[ZF]: break |
| if rep == "ne" and self.f[ZF]: break |
|
|