igc_exec: SCMEMA (screen-address seed) + gated sweep-pair adds
Verified flowing on the bench tile: s145 holds per-pixel x, scalar region packs it, SCAintoMEM constants land in eofr/eofb. Bars chain now breaks at the texz seed = the op-0x48-with-len family (0x3a804820 targets texz) -- FCMEMA, next to implement. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,8 @@ _reg(0x49, None, 'OP49', 1)
|
||||
_reg(0x30, None, 'OP30', 1)
|
||||
_reg(0x75, None, 'OP75', 1)
|
||||
_reg(0xdb, None, 'OPDB', 0)
|
||||
_reg(0x39, None, 'SCMEMA', 1) # write pixel screen-address into mem (seed)
|
||||
_reg(0xec, None, 'SCMEMA_IMM', 0) # bare .8-fixed immediate rider (e.g. 0xec00=236.0)
|
||||
|
||||
|
||||
def parse(words):
|
||||
@@ -254,21 +256,47 @@ class Tile:
|
||||
for i in range(NPIX):
|
||||
if not self.enab[i]:
|
||||
self.mem[i][a >> 3] &= ~(1 << (a & 7))
|
||||
elif m == 'SCMEMA':
|
||||
# seed: write the pixel's GLOBAL X screen address into mem[addr:len]
|
||||
_, addr, ln, operand = ins
|
||||
ln = max(1, min(20, ln if ln > 0 else 8))
|
||||
mask = (1 << ln) - 1
|
||||
for y in range(TILE_H):
|
||||
ybase = y * TILE_W
|
||||
for x in range(TILE_W):
|
||||
i = x + ybase
|
||||
if self.enab[i]:
|
||||
self._wr(self.mem[i], addr, ln, (x + self.ox) & mask)
|
||||
elif m == 'SWEEP21':
|
||||
# latch the src bit (secondary carry latch, does not clobber enable)
|
||||
_, dst, ln, operand = ins
|
||||
if operand is not None:
|
||||
src = operand & 0xff
|
||||
self._latch = [ (self.mem[i][src >> 3] >> (src & 7)) & 1
|
||||
for i in range(NPIX) ]
|
||||
elif m == 'SWEEP25':
|
||||
# bit-serial accumulate step: dst-field += src bit (best-effort:
|
||||
# treat the pair as part of a field ADD; the paired SWEEP21 reads
|
||||
# the src bit into the carry -- we implement the NET effect when
|
||||
# the operand gives {src,dst,len}: dst[0:len] += src bit << k is
|
||||
# approximated by a single-bit OR into dst (first pass).
|
||||
# gated add: if the latched src bit is set, add 1<<k into the
|
||||
# 20-bit dst field, where k = 20 - len2 (the emitter counts len2
|
||||
# down from 20) => net effect over the pair-cascade = dst += src.
|
||||
_, dst, ln, operand = ins
|
||||
if operand is None:
|
||||
continue
|
||||
src = operand & 0xff
|
||||
len2 = (operand >> 16) & 0x7f
|
||||
k = max(0, 20 - len2)
|
||||
latch = getattr(self, '_latch', None)
|
||||
if latch is None:
|
||||
continue
|
||||
add = 1 << k
|
||||
mask20 = (1 << 20) - 1
|
||||
for i in range(NPIX):
|
||||
if self.enab[i]:
|
||||
b = (self.mem[i][src >> 3] >> (src & 7)) & 1
|
||||
if b:
|
||||
self.mem[i][dst >> 3] |= 1 << (dst & 7)
|
||||
if self.enab[i] and latch[i]:
|
||||
v = (self._rd(self.mem[i], dst, 20) + add) & mask20
|
||||
self._wr(self.mem[i], dst, 20, v)
|
||||
else:
|
||||
unhandled.add(m)
|
||||
return unhandled
|
||||
|
||||
Reference in New Issue
Block a user