cc65 - Are % and * supported?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Goose2k
Posts: 33
Joined: Wed Dec 11, 2019 9:38 pm

cc65 - Are % and * supported?

Post by Goose2k » Fri May 22, 2020 1:50 pm

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

User avatar
dougeff
Posts: 2675
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: cc65 - Are % and * supported?

Post by dougeff » Fri May 22, 2020 1:53 pm

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)
Last edited by dougeff on Fri May 22, 2020 2:05 pm, edited 1 time in total.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
rainwarrior
Posts: 7804
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: cc65 - Are % and * supported?

Post by rainwarrior » Fri May 22, 2020 2:02 pm

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.
Last edited by rainwarrior on Fri May 22, 2020 2:31 pm, edited 1 time in total.

User avatar
Goose2k
Posts: 33
Joined: Wed Dec 11, 2019 9:38 pm

Re: cc65 - Are % and * supported?

Post by Goose2k » Fri May 22, 2020 2:15 pm

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.

User avatar
tokumaru
Posts: 11646
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: cc65 - Are % and * supported?

Post by tokumaru » Fri May 22, 2020 2:42 pm

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.

Post Reply