diff --git a/emulator/firmware-decomp/igc_exec.py b/emulator/firmware-decomp/igc_exec.py index 6a923c01..bcf3db51 100644 --- a/emulator/firmware-decomp/igc_exec.py +++ b/emulator/firmware-decomp/igc_exec.py @@ -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< 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