Another thing I learned is that if you are doing an HMOVE at cycle 73 rather than after WSYNC (to avoid the black "comb" lines, like in my Nyan Cat project), the HMxx values are different so that a zero actually moves the object. You would have to set each non-moving object's HMxx to #$80 instead.
Strobing HMOVE will raise a flag that causes horizontal blanking to be extended by 8 color clocks. Each sprite is essentially a counter that is not clocked during hblank, and so this will effectively move the sprite 8 pixels to the right (as it will take 8 more color clocks until the counter reaches the value that triggers rendering); the side effect are the black lines.
In order to facilitate other movement values, strobing HMOVE will trigger the TIA to start sending extra clock pulses that will drive the sprite counters. The amount of pulses that is sent to each sprite depends on the value of the high nibble of HMXX. The highest bit is internally inverted, so a value of 0 will cause 8 extra clocks, amounting to zero movement, 7 will cause 15 extra clocks, amounting to 7 pixels movement to the left.
During the visible part of the scanline, the extra clocks will interfere with the regular clock pulses. The details depend on the exact TIA revision; it is assumed that, on most chips, the extra clocks fall together with the regular ones and have no effect at all. Either way, this is the reason for the timing restrictions on HMOVE.
At the end of the scanline, the flag that prolongs hblank is cleared. If you strobe HMOVE before this, the extended blanking will not happen, and all extra clocks will cause a shift of one pixel to the left. This is the reason for the idiosyncrasies of late HMOVE. If you strobe HMOVE before the line ends **and** before the first extra clock is sent, you can achieve 15 pixels of movement to the left this way.
On a sidenote, this also explains most of the starfield effect: If you write HMxx while the extra pulses are sent, you can set it to a value below the extra pulse counter **before** the stop condition has been reached. This will cause the sprite to receive extra clocks until the next HMOVE and causes the starfield
Edited by DirtyHairy, Thu Dec 21, 2017 3:05 AM.