i860 emu: pipelined pftrunc/pfix through the adder pipe (raw-bits pipe entries)
The frame-1 extent bug traced to four `pftrunc.sd fN,f0,fX` ops (P=1) converting the region bounds through the A-pipe -- our fix/ftrunc was scalar-only (MAME's core never implemented the pipelined form: "pipelined not functional yet"). The drains then retired neighboring values (the homogeneous w=1.0f as raw bits -> y1=0x3F800000>>7=8323072 -> ~8.3M phantom tile rows = the 49K uniform bins / 4096 same-page descriptors). Pipe stages now carry (value, rp, raw): pipelined ftrunc/fix push the truncated integer BITS (64-bit pair for .sd results), and _retire() writes raw entries back verbatim instead of re-encoding floats. Extent probe after fix: x0=y0=x1=y1=0 (sane empty bound), single visit instead of a hot loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -425,13 +425,19 @@ class I860:
|
||||
# compiler's magic-constant float->int bit games come out exact), and the
|
||||
# retire is ENCODED with the pusher's precision, not the current op's.
|
||||
def _fp_pipes(self):
|
||||
if not hasattr(self, '_apipe') or (self._apipe and
|
||||
not isinstance(self._apipe[0], tuple)):
|
||||
pass
|
||||
elif self._apipe and len(self._apipe[0]) == 2: # migrate 2-tuple pipes
|
||||
self._apipe = [(v, r, None) for v, r in self._apipe]
|
||||
self._mpipe = [(v, r, None) for v, r in self._mpipe]
|
||||
if not hasattr(self, '_apipe') or (self._apipe and
|
||||
not isinstance(self._apipe[0], tuple)):
|
||||
# fresh init, or normalize legacy float-only snapshots
|
||||
old_a = getattr(self, '_apipe', [0.0] * 3)
|
||||
old_m = getattr(self, '_mpipe', [0.0] * 3)
|
||||
self._apipe = [(float(v), 1) for v in old_a]
|
||||
self._mpipe = [(float(v), 1) for v in old_m]
|
||||
self._apipe = [(float(v), 1, None) for v in old_a]
|
||||
self._mpipe = [(float(v), 1, None) for v in old_m]
|
||||
self._lpipe = [(0, None)] * 3 # pfld: (lo bits, hi bits | None)
|
||||
self._gpipe = [0] # graphics: raw 32-bit int
|
||||
self._kr = getattr(self, '_kr', 0.0)
|
||||
@@ -444,14 +450,26 @@ class I860:
|
||||
return val
|
||||
return self.b2f(self.f2b(val)) # round to single
|
||||
|
||||
def _padv(self, pipe, val, rp, depth):
|
||||
"""Push (val,rp) into stage 0; return the (val,rp) leaving stage depth-1."""
|
||||
def _padv(self, pipe, val, rp, depth, raw=None):
|
||||
"""Push a stage-entry; return the (val, rp, raw) leaving stage depth-1.
|
||||
raw is a raw bit pattern (32 or 64-bit int) for non-float results
|
||||
(pipelined ftrunc/fix), written back verbatim at retire."""
|
||||
out = pipe[depth - 1]
|
||||
for i in range(depth - 1, 0, -1):
|
||||
pipe[i] = pipe[i - 1]
|
||||
pipe[0] = (self._round_rp(val, rp), rp)
|
||||
pipe[0] = (self._round_rp(val, rp) if raw is None else val, rp, raw)
|
||||
return out
|
||||
|
||||
def _retire(self, dest, entry):
|
||||
val, rp, raw = entry
|
||||
if raw is None:
|
||||
self.wrf(dest, val, rp)
|
||||
elif rp:
|
||||
b0 = dest & ~1
|
||||
self.fwr(b0, raw & MASK32); self.fwr(b0 | 1, (raw >> 32) & MASK32)
|
||||
else:
|
||||
self.fwr(dest, raw & MASK32)
|
||||
|
||||
# PFAM/PFSM dual-op routing, decoded from the validated mnemonic grammar
|
||||
# (AS860 corpus: r2p1, r2pt, r2ap1, r2apt, i2p1.., rat1p2, m12apm, ra1p2,
|
||||
# m12tpm, m12tpa, iat1p2, ia1p2 ...):
|
||||
@@ -496,8 +514,8 @@ class I860:
|
||||
# sp = MULTIPLIER source precision; rp = ADDER source AND all results.
|
||||
ap, mp = self._fp_pipes()
|
||||
mdepth = 2 if sp else 3
|
||||
am_out, am_rp = ap[2]
|
||||
mm_out, mm_rp = mp[mdepth - 1]
|
||||
am_out, am_rp, am_raw = ap[2]
|
||||
mm_out, mm_rp, mm_raw = mp[mdepth - 1]
|
||||
pipe_val = am_out if pbit else mm_out # FLAGM operand + fdest bypass
|
||||
m1, m2, a1, a2, kload, tload = self._DUAL[sub & 0xf]
|
||||
def val(tag, prec):
|
||||
@@ -520,8 +538,8 @@ class I860:
|
||||
if kload: # K <- fsrc1 (mul precision)
|
||||
if m1 == 'ki': self._ki = self.rdf(src1, sp)
|
||||
else: self._kr = self.rdf(src1, sp)
|
||||
if pbit: self.wrf(dest, am_out, am_rp) # PFAM: fdest <- A retire
|
||||
else: self.wrf(dest, mm_out, mm_rp) # PFMAM: fdest <- M retire
|
||||
if pbit: self._retire(dest, ap[2]) # PFAM: fdest <- A retire
|
||||
else: self._retire(dest, mp[mdepth - 1]) # PFMAM: fdest <- M retire
|
||||
self._padv(ap, newa, rp, 3)
|
||||
self._padv(mp, newm, rp, mdepth)
|
||||
return
|
||||
@@ -530,10 +548,10 @@ class I860:
|
||||
if pbit:
|
||||
ap, mp = self._fp_pipes()
|
||||
depth = 3 if sub == 0x24 else (2 if sp else 3)
|
||||
out, orp = mp[depth - 1]
|
||||
out, orp, oraw = mp[depth - 1]
|
||||
if dest and src1 == dest: v1 = out # fdest bypass
|
||||
if dest and src2 == dest: v2 = out
|
||||
self.wrf(dest, out, orp)
|
||||
self._retire(dest, mp[depth - 1])
|
||||
self._padv(mp, v1 * v2, rp, depth)
|
||||
else:
|
||||
self.wrf(dest, v1 * v2, rp)
|
||||
@@ -541,12 +559,12 @@ class I860:
|
||||
v1 = self.rdf(src1, sp); v2 = self.rdf(src2, sp)
|
||||
if pbit:
|
||||
ap, mp = self._fp_pipes()
|
||||
out, orp = ap[2]
|
||||
out, orp, oraw = ap[2]
|
||||
if dest and src1 == dest: v1 = out # fdest bypass
|
||||
if dest and src2 == dest: v2 = out
|
||||
if sub == 0x33: r = v1
|
||||
else: r = (v1 - v2) if sub == 0x31 else (v1 + v2)
|
||||
self.wrf(dest, out, orp)
|
||||
self._retire(dest, ap[2])
|
||||
self._padv(ap, r, rp, 3)
|
||||
else:
|
||||
if sub == 0x33: r = v1
|
||||
@@ -559,15 +577,23 @@ class I860:
|
||||
import math
|
||||
b = self.rdf(src2, sp)
|
||||
self.wrf(dest, (1.0 / math.sqrt(b)) if b > 0 else 0.0, rp)
|
||||
elif sub in (0x32, 0x3a): # fix (round) / ftrunc -> int in FP reg
|
||||
elif sub in (0x32, 0x3a): # [p]fix / [p]ftrunc -> int bits
|
||||
a = self.rdf(src1, sp)
|
||||
if a != a or a in (float('inf'), float('-inf')):
|
||||
if a != a or a in (float('inf'), float('-inf')) or abs(a) > 0x7fffffff:
|
||||
iv = 0x80000000 # IEEE indefinite
|
||||
elif abs(a) > 0x7fffffff:
|
||||
iv = 0x80000000
|
||||
else:
|
||||
iv = int(a) if sub == 0x3a else int(a + (0.5 if a >= 0 else -0.5))
|
||||
self.fwr(dest & ~1 if rp else dest, iv & 0xFFFFFFFF)
|
||||
iv &= 0xFFFFFFFFFFFFFFFF if rp else 0xFFFFFFFF
|
||||
if pbit: # pipelined: through the adder pipe
|
||||
ap, mp = self._fp_pipes()
|
||||
self._retire(dest, ap[2])
|
||||
self._padv(ap, float(iv & 0xFFFFFFFF), rp, 3, raw=iv)
|
||||
elif rp:
|
||||
b0 = dest & ~1
|
||||
self.fwr(b0, iv & 0xFFFFFFFF)
|
||||
self.fwr(b0 | 1, (iv >> 32) & 0xFFFFFFFF)
|
||||
else:
|
||||
self.fwr(dest, iv & 0xFFFFFFFF)
|
||||
elif sub == 0x34: # fgt: CC = src1 > src2
|
||||
self.set_cc(self.rdf(src1, sp) > self.rdf(src2, sp))
|
||||
elif sub == 0x35: # feq: CC = src1 == src2
|
||||
|
||||
Reference in New Issue
Block a user