Page 1 of 1

cc65 - Are % and * supported?

Posted: Fri May 22, 2020 1:50 pm
by Goose2k
I am using CC65 compiler to build an NES game, and I thought that I was not able to use %, *, and / operators.

However, on a whim, I just tried it, and it worked. Is it supprted, but just very slow or something?

C++:

Code: Select all

return game_board[(y * 10) + (x % 10)];
Generated ASM:

Code: Select all

	ldx     #$00
	lda     (sp),y
	jsr     mulax10
	jsr     pushax
	ldy     #$03
	lda     (sp),y
	jsr     pusha0
	lda     #$0A
	jsr     tosumoda0
	jsr     tosaddax
	sta     ptr1
	txa
	clc
	adc     #>(_game_board)
	sta     ptr1+1
	ldy     #<(_game_board)
	ldx     #$00
	lda     (ptr1),y

Re: cc65 - Are % and * supported?

Posted: Fri May 22, 2020 1:53 pm
by dougeff
It is slow, except for CHAR and powers of 2, which are optimized to bit shifts.

var = var * 2

lda var
asl a
sta var

var = var / 2

lda var
lsr a
sta var

(I'm not 100% sure this is true at the moment)

Re: cc65 - Are % and * supported?

Posted: Fri May 22, 2020 2:02 pm
by rainwarrior

Code: Select all

* 10
became mulax10, which is a dedicated subroutine for multiplying by 10, and is pretty efficient. CC65 does have dedicated ones for 3, 5, 6, 7, 9, and 10. Powers of two are generally handled with reasonably efficient shifts. (More simply: 0-10 and other powers of 2 are efficient.) Other numbers will use a more generic and slower iterative multiply subroutine.

Code: Select all

% 10
became tosumoda0, which in turn calls a generic iterative division subroutine (udiv16). This is relatively slow.

It's not at all unreasonable to do some multiplication or division in your program. Just because it's slower than addition or subtraction doesn't mean it can't be fit into a performance budget.

You can analyze the code and understand the algorithms to get a sense of their (in)efficiency, but the easiest way to figure this stuff out is just to measure the code and see how many cycles it takes. If it's too many, then look at a different approach, if not, just carry on.

However, an immediate and simple suggestion is to make game board 16 wide, because multiply and modulo by 16 is generally fast (power of 2). Even if you don't use the extra 6 bytes on the end of each row, the extra 60 wasted bytes will still get you back a lot of performance if you're going into that array a lot.

Re: cc65 - Are % and * supported?

Posted: Fri May 22, 2020 2:15 pm
by Goose2k
Thanks for the replies. Very informative!
rainwarrior wrote:
Fri May 22, 2020 2:02 pm
However, an immediate and simple suggestion is to make game board 16 wide, because multiply and modulo by 16 is generally fast (power of 2). Even if you don't use the extra 6 bytes on the end of each row, the extra 60 wasted bytes will still get you back a lot of performance if you're going into that array a lot.
That's what I was thinking as well (and something Doug did in his tutorial for breakout), prior to trying mod/mult.

Re: cc65 - Are % and * supported?

Posted: Fri May 22, 2020 2:42 pm
by tokumaru
The fact that the 6502 doesn't do multiplication and division natively doesn't mean that those operations are impossible, it just means that they'll be slow, due to being implemented algorithmically, through combinations and repetitions of several instructions that the 6502 does have.

The same goes for manipulating 16-bit (and larger) values, which the 6502 can do just fine in spite of being an 8-bit CPU... It just has to do it one byte at a time, making it slower than CPUs that can manipulate multiple bytes at a time.

It's perfectly okay to use multiplications and divisions in NES programs sparingly, in the few cases where you can't use powers of 2. As long as you don't do dozens of these operations per frame you should be fine.