5

In the past, the only assembly programming I've done has been a tiny bit of ARM, and then a larger game project in 68k.

In 68k I was used to being able to do things like add.l d0, d1 to add the value in d0 to d1. I've just started playing around with some 6502 development on the Atari 2600 for the first time, and it appears as though you can't add the value of the X or Y registers to the accumulator.

Is the only way to add the value in X to write it out to memory with an stx and then perform a subsequent adc to add to the accumulator from that memory address?

2 Answers 2

7

In 68k I was used to being able to do things like add.l d0, d1 to add the value in d0 to d1. I've just started playing around with some 6502 development on the Atari 2600 for the first time, and it appears as though you can't add the value of the X or Y registers to the accumulator.

Think of it like the 68k's distinction between data and address registers. A is the generic data register, all data operations (*1) are done on A. X/Y are index registers with the only purpose to add an index to a direct or indirect address.

Is the only way to add the value in X to write it out to memory with an stx and then perform a subsequent adc to add to the accumulator from that memory address?

One obvious way is using a table like Tommy already mentioned. Such a table can be used for many more programming tricks (*2). Except, on a VCS ROM is almost as rare as RAM. a 256 byte table occupies already 1/16th of the address space available (*3). Then again, space can be saved when the range of the value to be added is known.

A special way to do operations on a 2600 is to use the stack, as it shares RAM with the zero page. Usually the content of the stack pointer is well known, thus a combination of PHA, TXA and ADC zp, using the known stack location will work as well.

Of course this depends a lot on how stack is used in your program. In general it is more appropriate to adept programming style to how the 6502 is designed/intended to be used - like with every CPU.

The 6502 is a special beast and 2600 programming a neat playground, isn't it?


*1 - Except INC/DEC which has been added with the 65C02.

*2 - For example by extending the table it can be used to add constants to index registers, like when walking a sprite table.

*3 - The address space for ROM is 4 KiB. While there are multiple pages possible, a table can only be used from code within the same ROM page. So the table either needs to be copied into each ROM page that uses it, or a page flip has to be done - which is for sure more expensive than a STX/ADC combination.

5
  • I was using the stack for storage last night, but I was thinking that I couldn't add from the stack... didn't occur to me that I could use adc with the address in the SP! The 2600 really is kooky. I've read Racing the Beam, but even that didn't quite prepare me for manually sending VSYNC and VBLANK lines :)
    – Matt Lacey
    Jan 23, 2020 at 23:50
  • 1
    @MattLacey Well, you can't use SP, you got to know it. Then again, VCS code is rather dense when it comes to stack usage, so stack locations are almost like static assigned. Also, do not use the stack for intermediate storage. Use preassigned ZP addresses. It saves several cycles compared with stack. It's all about using the resources given. No boring programs, but building a game machine with interleaving cogwheels. I really like it.
    – Raffzahn
    Jan 24, 2020 at 0:06
  • 1
    Ok, that makes sense! Will have another play tonight. Got a sprite on screen (moving vertically) with multiple colours, just want to animate it as well. Wish I had more registers :D
    – Matt Lacey
    Jan 24, 2020 at 0:32
  • 1
    You can do something like PHX / TSX / ADC $101, x in a generic 6502 if you can’t know the stack pointer ahead of time and don’t mind clobbering x. But it’s not speedy. And on a 2600 you can use the zero-page indexed rather than the absolute, obviously.
    – Tommy
    Jan 24, 2020 at 0:38
  • @MattLacey Yes, works as well. Usually some way works great for most cases and a given CPU (here the STX/ADC). They make a good building block to be reused whenever needed. Except in a very tight environment like the 2600. It's unforgiving to average good solutions. It's all about producing the absolute best solution. Here not just the way you code, but as well the over all design, even the task to be done has to be reevaluated every time. If there's no time for a 4th sprite, you need to redesign the game mechanics to work with 3 - or turn you shooter into a logic puzzle :)) I'm loving it ...
    – Raffzahn
    Jan 24, 2020 at 0:55
7

That's not strictly the only way — if you had 256 bytes to spare (/waste) on a lookup table of f(n)=n then you could do something like:

.table db $00, $01, $02, $03 ... $ff

ADC table,x

But, otherwise, no, there is no built-in way to perform arithmetic between registers.

7
  • 2
    I think I got ruined by 68k, with 8 data registers and 7 address registers to play with :)
    – Matt Lacey
    Jan 23, 2020 at 23:19
  • 10
    Ah, think of the zero page as being registers instead.
    – PeterI
    Jan 23, 2020 at 23:30
  • 2
    @MattLacey I wouldn't say you got "ruined". The early 8-bit CPUs are all accumulator-based machines ( en.wikipedia.org/wiki/… ), the programming techniques for them are very different from a general-purpose-register-based machine - it takes time to be familiar with them. Jan 23, 2020 at 23:53
  • 2
    I don’t know how apocryphal this is, but the version I heard was that RAM was so much faster than processors in the 1970s that the design of the 6502 is explicitly predicated on that being the case. To the point where it, like the 6800, spends only half of each cycle doing the RAM signalling — memory bandwidth just isn’t treated as a bottleneck.
    – Tommy
    Jan 24, 2020 at 0:16
  • That makes sense - my 68k work was on the Falcon where the 32bit CPU is hampered by a 16bit bus
    – Matt Lacey
    Jan 24, 2020 at 0:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .