# Fastest way to write 0x00 to a zero-page memory location? (6502, Atari 2600)

I have a kernel in my 6502 game that writes two dots to a sprite, so for example:

``````........
........
.XX..XX.
.XX..XX.
........
........
``````

Either 0, 1, or 2 dots can be on at a time. This is done one scanline at a time, so we're only looking at how to write the middle two lines.

So far I've implemented this by doing the following:

1. The accumulator is set to 0b01100000
2. X is set to 0b00000110
3. For the left dot, I use `STA \$1B` (3 cycles) to only turn that dot on.
4. For the right dot, I use `STX \$1B` (3 cycles) to turn that dot on.
5. For both dots, I can use the undocumented instruction SAX (\$87) to write A | X to the value, so `SAX \$1B` (3 cycles) to turn both on.

But if I need to turn both dots off, the quickest way I know of to write 0b00000000 to a register is to store \$00 in Y and then write it. Of course, this means I can't use Y for other purposes in my code.

I don't need a trick that takes 3 cycles (4 or 5 are fine) but are there any possibilities, without consuming a register, to write 0x00 to a memory location in zero page on the 6502?

EDIT: The above description of the problem is incorrect (see comments). I actually set A=01100000, X=00000110, Y=01100110, and use SAX to write \$00. The question as posed (writing 0x00 to a register without storing 0x00 in a register) is still answered in the replies.

• It's late so I'm probably being an idiot but why is `SAX` not writing zero? The values you say are in `A` and `X` have no set bits in common. Jul 9, 2018 at 2:13
• I'm not familiar with the 6502, but a common trick on x86 was to XOR a value with itself (x XOR x = 0, for any x; on x86, a register-to-register XOR encoded in two bytes instead of three for a 16-bit register store, so you'd save a byte by doing so). Might that work on the 6502?
– user
Jul 9, 2018 at 8:57
• @MichaelKjörling alas there are no register-to-register XORs (/EORs) on the 6502. Unrelated: the 65C02 added `STZ`, store zero, which would have been perfect here. Jul 9, 2018 at 13:30
• Also, I really think `SAX` writes the and, not the or. E.g. oxyron.de/html/opcodes02.html or, to quote nesdev.com/6502_cpu.txt : "Many undocumented commands do not use AND between registers, the CPU just throws the bytes to a bus simultaneously and lets the open-collector drivers perform the AND. I.e. the command called 'SAX', which is in the STORE section (opcodes \$A0...\$BF), stores the result of (A & X) by this way." (though that should be e.g. not i.e.) Jul 9, 2018 at 13:32
• Not directly addressing the question of a faster way to write 0, but is it maybe an option to reformulate and instead put the desired dot bit pattern %00, %01, %10, %11 in an index register, and do a lookup into a 4 value table translating it to %00000000, %00000110, % 01100000, %01100110 ? Jul 9, 2018 at 13:42

My second bite of the cherry: another of the undocumented opcodes is SYA/SHY/SAY which will:

AND Y register with the high byte of the target address of the argument + 1. Store the result in memory.

If you were willing and able to switch your usage of `X` and `A` then you could have `01100000` in X, therefore the argument you supply to `SAY` would be `001b - b01100000` = `ffbb`:

``````9C bb ff          ; SAY \$ffbb,x
``````

So that would store `Y & (ff+1)` to `ffbb + b01100000`, i.e. it would store `Y & 0 = 0` to `1b`, in five cycles. Your `Y` can hold anything, and isn't affected.

• Thank you! Using SAY and XAS make this possible! `ldx #%01100110; ldy #00` then `.byte \$9e, GRP0, #%000001110` for right dot, `.byte \$9e, GRP0, #%111100000` for left dot, `stx GRP0` for both dots, and `sty GRP0` for neither. Accumulator is unaffected :)
– trim
Jul 11, 2018 at 0:46
• Glad I could help eventually, even if only obliquely! Jul 11, 2018 at 2:08